Last active
December 28, 2015 03:29
-
-
Save philcleveland/7435552 to your computer and use it in GitHub Desktop.
RxUI Search example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public partial class App : Application | |
{ | |
protected override void OnStartup(StartupEventArgs e) | |
{ | |
base.OnStartup(e); | |
//ghetto bootstrap - IS THIS OK? | |
var searchView = new SearchView(); | |
searchView.ViewModel = new SearchViewModel(); | |
searchView.DataContext = searchView.ViewModel; | |
var mw = new AppShell(searchView); | |
mw.Show(); | |
} | |
} | |
public AppShell(SearchView searchView) | |
{ | |
InitializeComponent(); | |
this.MainPanel.Children.Add(searchView); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<UserControl x:Class="FeedManagement.WPF.Search.SearchView" | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |
xmlns:v="clr-namespace:FeedManagement.WPF.Search" | |
mc:Ignorable="d" | |
d:DesignHeight="300" d:DesignWidth="300"> | |
<UserControl.Resources> | |
<DataTemplate DataType="{x:Type v:SearchViewModel}"> | |
<v:SearchView ViewModel="{Binding}"/> | |
</DataTemplate> | |
</UserControl.Resources> | |
<Grid> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition/> | |
</Grid.ColumnDefinitions> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="1*"/> | |
<RowDefinition Height="8*"/> | |
</Grid.RowDefinitions> | |
<Grid Grid.Row="0"> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition Width="Auto"/> | |
<ColumnDefinition/> | |
<ColumnDefinition Width="Auto"/> | |
</Grid.ColumnDefinitions> | |
<Label>Search</Label> | |
<TextBox x:Name="SearchText" Grid.Column="1"></TextBox> | |
<Button x:Name="SearchButton" Grid.Column="2" Content="{StaticResource Icons.Search}" ></Button> | |
</Grid> | |
<DockPanel Grid.Row="1"> | |
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> | |
<ListBox x:Name="TweetTiles" > | |
</ListBox> | |
</ScrollViewer> | |
</DockPanel> | |
</Grid> | |
</UserControl> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public partial class SearchView : UserControl , IViewFor<SearchViewModel> | |
{ | |
public SearchView() | |
{ | |
InitializeComponent(); | |
//2 way bind between the view and view model of the search text | |
this.Bind(ViewModel, vm => vm.SearchText, v=>v.SearchText.Text); | |
//one way bind from the view model prop TweetTiles to the view TweetTiles.ItemsSource | |
this.OneWayBind(ViewModel, vm => vm.TweetTiles, v => v.TweetTiles.ItemsSource); | |
//binds the search command, defined on viewmodel, to the view SearchButton | |
this.BindCommand(ViewModel, vm => vm.SearchCommand, v => v.SearchButton); | |
} | |
//The interface implementation needs to be a DependencyProperty, so that RUI | |
//can pick up on view model changes. make sure that the viewmodel type matches | |
//the type declared in IViewFor<xxx> (e.g. is it an interface?) | |
public static readonly DependencyProperty ViewModelProperty = | |
DependencyProperty.Register("ViewModel", typeof(SearchViewModel), typeof(SearchView), new PropertyMetadata(null)); | |
public SearchViewModel ViewModel | |
{ | |
get { return (SearchViewModel)GetValue(ViewModelProperty); } | |
set { SetValue(ViewModelProperty, value); } | |
} | |
object IViewFor.ViewModel | |
{ | |
get { return ViewModel; } | |
set { ViewModel = (SearchViewModel)value; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SearchViewModel : ReactiveObject, ISearchViewModel | |
{ | |
private Twitter _twitterAPI = new Twitter(); | |
public ReactiveCommand SearchCommand { get; set; } | |
private ObservableAsPropertyHelper<List<TwitterTileViewModel>> _TweetTiles; | |
public List<TwitterTileViewModel> TweetTiles | |
{ | |
get | |
{ | |
return _TweetTiles.Value; | |
} | |
} | |
public SearchViewModel() | |
{ | |
SearchCommand = new ReactiveCommand(null, false, null); | |
var results = SearchCommand.RegisterAsyncTask(t => Task.Factory.StartNew(() => _twitterAPI.SearchFor(SearchText))) | |
.Select(x => ConvertTweets(x)); | |
SearchCommand.ThrownExceptions | |
.Subscribe(ex => this.Log().WarnException("Twitter Search Failed", ex)); | |
_TweetTiles = new ObservableAsPropertyHelper<List<TwitterTileViewModel>>(results, vm => { this.RaisePropertyChanged("TweetTiles"); }); | |
} | |
List<TwitterTileViewModel> ConvertTweets(List<Tweet> tweets) | |
{ | |
var tempTiles = new List<TwitterTileViewModel>(); | |
tweets.ForEach(tweet => tempTiles.Add(new TwitterTileViewModel(tweet))); | |
return new List<TwitterTileViewModel>(tempTiles); | |
} | |
private string _searchText = ""; | |
public string SearchText | |
{ | |
get { return _searchText; } | |
set { _searchText = value; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
System.NullReferenceException was unhandled | |
HResult=-2147467261 | |
Message=Object reference not set to an instance of an object. | |
Source=ReactiveUI.Xaml | |
StackTrace: | |
at ReactiveUI.Xaml.ViewModelViewHost.<.ctor>b__5(<>f__AnonymousType2`2 x) | |
at System.Reactive.AnonymousSafeObserver`1.OnNext(T value) | |
at System.Reactive.Linq.Observαble.CombineLatest`3._.F.OnNext(TFirst value) | |
at System.Reactive.Linq.Observαble.Select`2._.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.DistinctUntilChanged`2._.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.Select`2._.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.Where`1._.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.Switch`1._.ι.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.Concat`1._.OnNext(TSource value) | |
at System.Reactive.Linq.Observαble.Select`2._.OnNext(TSource value) | |
at System.Reactive.AutoDetachObserver`1.OnNextCore(T value) | |
at System.Reactive.ObserverBase`1.OnNext(T value) | |
at ReactiveUI.Xaml.DependencyObjectObservableForProperty.<>c__DisplayClass4.<>c__DisplayClass6.<GetNotificationForProperty>b__2(Object o, EventArgs e) | |
at MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(DependencyObject d, DependencyPropertyChangedEventArgs args) | |
at System.Windows.DependentList.InvalidateDependents(DependencyObject source, DependencyPropertyChangedEventArgs sourceArgs) | |
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) | |
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) | |
at System.Windows.StyleHelper.ApplyTemplatedParentValue(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, DependencyProperty dp, FrameworkElementFactory templateRoot) | |
at System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, Boolean isDetach, FrameworkElementFactory templateRoot) | |
at System.Windows.FrameworkTemplate.InvalidatePropertiesOnTemplate(DependencyObject container, Object currentObject) | |
at System.Windows.FrameworkTemplate.HandleBeforeProperties(Object createdObject, DependencyObject& rootObject, DependencyObject container, FrameworkElement feContainer, INameScope nameScope) | |
at System.Windows.FrameworkTemplate.<>c__DisplayClass6.<LoadOptimizedTemplateContent>b__3(Object sender, XamlObjectEventArgs args) | |
at System.Xaml.XamlObjectWriter.OnBeforeProperties(Object value) | |
at System.Xaml.XamlObjectWriter.Logic_CreateAndAssignToParentStart(ObjectWriterContext ctx) | |
at System.Xaml.XamlObjectWriter.WriteEndObject() | |
at System.Xaml.XamlWriter.WriteNode(XamlReader reader) | |
at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter) | |
at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter) | |
at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField) | |
at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren) | |
at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate) | |
at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container) | |
at System.Windows.FrameworkElement.ApplyTemplate() | |
at System.Windows.FrameworkElement.MeasureCore(Size availableSize) | |
at System.Windows.UIElement.Measure(Size availableSize) | |
at System.Windows.Controls.Border.MeasureOverride(Size constraint) | |
at System.Windows.FrameworkElement.MeasureCore(Size availableSize) | |
at System.Windows.UIElement.Measure(Size availableSize) | |
at System.Windows.Controls.Control.MeasureOverride(Size constraint) | |
at System.Windows.FrameworkElement.MeasureCore(Size availableSize) | |
at System.Windows.UIElement.Measure(Size availableSize) | |
at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUniformOrAverageContainerSize, Boolean& computedAreContainersUniformlySized, IList& items, Object& item, IList& children, Int32& childIndex, Boolean& visualOrderChanged, Boolean& isHorizontal, Size& childConstraint, Rect& viewport, VirtualizationCacheLength& cacheSize, VirtualizationCacheLengthUnit& cacheUnit, Boolean& foundFirstItemInViewport, Double& firstItemInViewportOffset, Size& stackPixelSize, Size& stackPixelSizeInViewport, Size& stackPixelSizeInCacheBeforeViewport, Size& stackPixelSizeInCacheAfterViewport, Size& stackLogicalSize, Size& stackLogicalSizeInViewport, Size& stackLogicalSizeInCacheBeforeViewport, Size& stackLogicalSizeInCacheAfterViewport, Boolean& mustDisableVirtualization, Boolean isBeforeFirstItem, Boolean isAfterFirstItem, Boolean isAfterLastItem, Boolean skipActualMeasure, Boolean skipGeneration, Boolean& hasBringIntoViewContainerBeenMeasured, Boolean& hasVirtualizingChildren) | |
at System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable`1& lastPageSafeOffset, List`1& previouslyMeasuredOffsets, Boolean remeasure) | |
at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint) | |
at System.Windows.FrameworkElement.MeasureCore(Size availableSize) | |
at System.Windows.UIElement.Measure(Size availableSize) | |
at System.Windows.ContextLayoutManager.UpdateLayout() | |
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg) | |
at System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork() | |
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks() | |
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget) | |
at System.Windows.Media.MediaContext.AnimatedRenderMessageHandler(Object resizedCompositionTarget) | |
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) | |
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) | |
at System.Windows.Threading.DispatcherOperation.InvokeImpl() | |
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) | |
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) | |
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) | |
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) | |
at System.Windows.Threading.DispatcherOperation.Invoke() | |
at System.Windows.Threading.Dispatcher.ProcessQueue() | |
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) | |
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) | |
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) | |
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) | |
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) | |
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) | |
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) | |
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) | |
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) | |
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) | |
at System.Windows.Threading.Dispatcher.Run() | |
at System.Windows.Application.RunDispatcher(Object ignore) | |
at System.Windows.Application.RunInternal(Window window) | |
at System.Windows.Application.Run(Window window) | |
at System.Windows.Application.Run() | |
at FeedManagement.WPF.App.Main() in c:\Users\phil.SONOCINE\Documents\Visual Studio 2013\Projects\FeedReaders\FeedManagement.WPF\obj\Debug\App.g.cs:line 0 | |
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) | |
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) | |
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() | |
at System.Threading.ThreadHelper.ThreadStart_Context(Object state) | |
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) | |
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) | |
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) | |
at System.Threading.ThreadHelper.ThreadStart() | |
InnerException: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On line 19 of SearchViewModel, you're setting SearchText on a non-UI thread. Instead, write it this way:
Also, the property setter on line 42 should be written as:
As the name implies,
RaiseAndSetIfChanged
only does something if the property changes. But since you updated the field yourself, the property is always equal according toRaiseAndSetIfChanged