binding to dynamic resource in ItemsControl on the ItemsSource Property - c#

Hey I was hoping someone could answer a couple questions for me. How am I supposed to ensure that the bound data to itemsource updates dynamically? I can't change bindingsource from staticresource to dynamic resource because the Source Property of the Object Binding is not a dependency property of a dependency object.
What does binding to a staticresource mean exactly? I would think that binding to a dynamicresource would mean that the dependencyproperty updates when the resource changes.
Does binding to a static resource merely attach the resource's initial value?
My goal is just to have signal_viewer update based on the signal_data.
<UserControl.Resources>
<wpfExp:SignalData x:Key="signal_data" />
</UserControl.Resources>
<DockPanel x:Name ="maindockpanel" Height ="Auto" Width ="Auto" LastChildFill="True">
<ToolBarTray DockPanel.Dock="Top">
<ToolBar HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Button Name="load_button" Height="20" Width="Auto" Click="Load_Button_Click">Load</Button>
<Button Name="zoom_in_button" Click="zoom_in_button_Click">Zoom In</Button>
<Button Name="zoom_out_button" Click="zoom_out_button_Click">Zoom Out</Button>
</ToolBar>
</ToolBarTray>
<ItemsControl x:Name ="Signalviewer_Control" ItemsSource="{Binding Source = {StaticResource signal_data}, Path = list_of_signals}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<wpfExp:SignalViewer Signal="{Binding}" MainText="{Binding Path = SignalName}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

I'm all against putting the ViewModel or data as a Resource in XAML due to all these issues you mentioned.
Instead, either assign the DataContext in code behind:
public SomeWindow() //Window Constructor
{
DataContext = new SomeViewModel();
}
or use ViewModelLocator
or use the RegisterDataTemplate approach outlined here.
Anyways, if you want to resolve this quickly, change your list_of_signals from List<T> to an ObservableCollection<T>

Related

Bind view model to content control/presenter

on uwp, I want to make a hamburger menu with custom icon in xaml. from the lunch scheduler sample from MS, I try to bind a viewmodel property to a content element in a view like :
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="viewmodels:MenuItem">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{x:Bind Icon2}" />
where Icon is a property like
Icon2 = Application.Current.Resources["BookIcon"],
which works and retreive a viewbox containing a canvas
but I got an exception "Value does not fall within the expected range."
Did some know if it's possible like in WPF ??
nb : if i put the canvas directly in the contentcontrol, it works. perhaps the binding does not accept anything else than string
i found a solution, convert the viewbox to DataTemplate and bind to ContentTemplate
<DataTemplate x:Key="BookIcon">
<Viewbox Width="48" Height="48">
<Canvas Width="24" Height="24">
<Path Data/>
</Canvas>
</Viewbox>
</DataTemplate>
and
<ContentControl ContentTemplate="{x:Bind Icon2}"/>
any other solution is welcome

WPF UserControl.Resources reference

I am try to start learning WPF and i am using Telerik.
So i start with simple ComboBox in this article and this is my control:
<telerik:RadComboBox Height="20" Width="200" ItemsSource="{Binding Source={StaticResource DataSource}, Path=Agency}"></telerik:RadComboBox>
What i am trying to do now is to bind an object but first to declare a resource in the XAML (from the article):
<UserControl.Resources>
<example:AgencyViewModel x:Key="DataSource"/> // AgencyViewModel is a class
</UserControl.Resources>
So my problem is that after UserControl i don't have the option Resources, i try to put it inside my control, so i be happy to understand how this is working in WPF
You have to set the DataContext dependency property on a parent control in relation to your ComboBox. The DataContext is then inherited by all (logical-)children. You can then bind to properties on the object referenced by the DataContext dependency property. You do that by referencing the x:Key of your resource with a StaticResource Markup Extension construct.
<UserControl>
<UserControl.Resources>
<example:AgencyViewModel x:Key="DataSource"/> // AgencyViewModel is a class
</UserControl.Resources>
<Grid DataContext="{StaticResource DataSource}">
<telerik:RadComboBox Height="20" Width="200"
ItemsSource="{Binding ItemsCollectionDefinedInViewModel}" />
</Grid>
</UserControl>
You can also do it as it is done in the article without setting the DataContext but instead setting the Source of the binding explicilty.
ItemsSource="{Binding Source={StaticResource DataSource}, Path=Agency}"

How to binding data to and register property in user controls WP8

I have a user controls:
<UserControl>
<Grid Name="grid1" Background="#1133CC" Canvas.ZIndex="1" Width="200" Height="200">
<Image Name="img1" Source="{Binding ImageSource}" />
<TextBlock Text="{Binding Title"}/>
</Grid>
</UserControls>
Title: string
ImageSource: BitmapImage
How to use binding data in MainPage.xaml like:
<Grid>
<local:myUserControl Title="{Binding Title"} ImageSoure="{Binding ImageSource}" />
</Grid>
How to do that? Thanks
Sounds like you're basically asking "How do I do binding". A good read is: http://msdn.microsoft.com/en-us/magazine/hh852595.aspx and nearly any other Binding resource you find out there.
In your case you will need an object that has a Title and a ImageSource property that is set as the DataContext of the control (or one of its parents like the PhoneApplicationPage). You can set the DataContext from your code behind (or in XAML) (if you're on the Page then you can simple set DataContext = ....

WPF Binding a Dependency Property

I am having an issue binding a dependency property in a UserControl. When it initializes it gets a value but then it will not update. I've probably missed something obvious, here are some code snippets:
This is where I bind the BalanceContent dependency property:
<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4"
BalanceContent="{Binding Source={StaticResource UserData}, Path=SelectedUser.Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</Game:PlayerDetails>
Here is the TextBox in the UserControl:
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=BalanceContent}"
Grid.Row="7"></TextBox>
Here is the Dependency Property:
public static readonly DependencyProperty BalanceContentProperty = DependencyProperty.Register(
"BalanceContent", typeof(string), typeof(PlayerDetails));
public string BalanceContent
{
get
{return (string) GetValue(BalanceContentProperty);}
set
{SetValue(BalanceContentProperty, value);}
}
Here is the list where the selected user is updated, which is in a view that uses the UserControl:
<ListView x:Name="lstAccounts" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="4"
ItemsSource="{Binding Source={StaticResource UserData}, Path=CurrentUserSearch}"
SelectedItem="{Binding Source={StaticResource UserData}, Path=SelectedUser}"
And SelectedUser is defined here in a class that implements INotifyPropertyChanged:
public User SelectedUser
{
get
{
return _selectedUser;
}
set
{
_selectedUser = value;
OnPropertyChanged(new PropertyChangedEventArgs("SelectedUser"));
}
}
The idea is that the TextBox should update when a new user is selected in the list but at the moment it is not doing so. I've put the binding on local TextBox and it updates fine, just not on a DependencyProperty. Any help appreciated.
There are some possibilities you could try:
First, your ListView may not be updating yours ViewModel's SelectedUser property. Try setting the binding in your ListView to "TwoWay" mode:
<ListView x:Name="lstAccounts" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="4"
ItemsSource="{Binding Source={StaticResource UserData}, Path=CurrentUserSearch}"
SelectedItem="{Binding Source={StaticResource UserData}, Path=SelectedUser, Mode=TwoWay}"/>
You can organize better the way the DataContext's are defined. Remember that all the child controls of your UserControl will have access to its DataContext without the use of relative binding (they inherit it). As your PlayerInfo control depends on the SelectedUser, consider setting it's DataContext to the SelectedUser, either binding it to the SelectedUser of the ListView or the SelectedUser in the UserData viewmodel.
<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{Binding Source={StaticResource UserData}, Path=SelectedUser}"
BalanceContent="{Binding Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</Game:PlayerDetails>
The source of the current SelectedUser could also be the ListView:
<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{Binding SelectedItem, ElementName=lstAccounts}"
BalanceContent="{Binding Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</Game:PlayerDetails>
Either way, you will then be able to do the following on the TextBox, because its DataContext will be the same as the one of its parent:
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding Balance}"
Grid.Row="7"></TextBox>
If the usercontrol depends on the root viewmodel for things like commands and other high level logic, then set the DataContext to it in a way you can easily access the SelectedUser.
<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{StaticResource UserData}"
BalanceContent="{Binding SelectedUser.Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</Game:PlayerDetails>
So you can do this:
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding SelectedUser.Balance}"
Grid.Row="7"></TextBox>
In this second approach, however, you will have to check one thing I'm not sure about. I know that when the DataContext of a control changes, it will update all the dependent bindings allright. For example, if you changed the PlayerDetails DataContext to another UserData instance, the BalanceContent property would update as well. However, in this case the BalanceContent depends on property of the SelectedUser of the UserData. So it will listen to Property changes of that instance of User. If the SelectedUser.Balance changes (and User implements INotifyPropertyChanged, or it is a DependencyProperty), BalanceContent will update. Now, if the SelectedUser instance in the UserData changes, I'm not sure BalanceContent will update, because I think that a binding does not listen to changes of every object in its path.
EDIT
The last point was perhaps the first problem I hit when developing with xaml. I had a DataGrid in Silverlight whose entity type had a property of a complex type. One of the columns depended on a property of the complex type. If I changed the value of the complex type, the column would update fine (it implemented INPC). If I changed the complex type instance of an entity, the column would not... The solution was to cascade DataContexts: I created a template column, set the binding of the column for the complex type, instead of its property. Then I bound the text of the TextBox of my template to the property of the complextype, because it was now the TextBox's DataContext.
In your case you can do it for the TextBox.Text, but not for the PlayerDetails.BalanceContent. You can bind the TextBox.DataContext to the SelectedUser of the UserData and then bind Text to the Balance property.
<TextBox VerticalAlignment="Center" DataContext="{Binding SelectedUser}" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding Balance}"
Grid.Row="7"></TextBox>
Please try testing after changing your binding for text box inside your user control to bind to BalanceContent which is User Controls Dependency Property (your original binding source seems to be data context property)
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=BalanceContent}"
EDIT: Please try the following code
public User SelectedUser
{
get
{
return _selectedUser;
}
set
{
_selectedUser = value;
OnPropertyChanged(new PropertyChangedEventArgs("SelectedUser"));
OnPropertyChanged(new PropertyChangedEventArgs("SelectedUserBalance"));
}
}
public string SelectedUserBalance
{
get
{
return _selectedUser.Balance;
}
}
<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4"
BalanceContent="{Binding Source={StaticResource UserData}, Path=SelectedUserBalance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</Game:PlayerDetails>
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=BalanceContent}"
Grid.Row="7"></TextBox>
The Textbox is trying to bind to the UserControls DataContext. give an x:Name to the Usercontrol definition and set the TextBox's DataContext to DataContext="{Binding ElementName=[YourControlName]}"
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding SelectedItem.BalanceContent, ElementName=lstAccounts}" Grid.Row="7"></TextBox>
forget binding of UserControl , Directly bind TextBox to SelectedItem . I hope this will help.
You are binding a StaticResource to the property. StaticResources, as opposed to DynamicResources, are loaded only once, when the Window (or UserControl) is being initialised. DynamicResources are loaded only when needed (and each time when needed). Any change that is made to a DynamicResource is picked up immediately and the property is updated accordingly. Simply replace the keyword "StaticResource" with "DynamicResource", and the property binding should update each time the resource changes.
Note: If the StaticResource is an object that derives from the Freezable class, it will also behave somewhat like a DynamicResource. For example, if your resource is a Brush, the bound property will update each time you change the Brush object in any way (by changing its opacity, for example), but this is due to the behaviour inherited from the Freezable class. However if you replace the Brush object in the StaticResource by a new Brush object, this change won't be picked up, because the change has been made to the Resource, which is Static, not the Brush.
Also Note: Even resources that are only available as StaticResources, such as data SystemColors, SystemFonts (which provide access to system settings) can be wrapped in a DynamicResource to ensure that the property is updated at each change. This can be done this way:
<Control Property="{DynamicResource {x:Static SystemColors.XXX}}"></Control>.

WPF: Accessing two DataContexts in the same control

I am using an MVVM approach, and I have an object from my ViewModel called DatabasesSubFrame which is DataTemplated to show a ListBox. I want to display a Button below the ListBox, which binds to both the currently SelectedItem, and a property on the DatabasesSubFrame object which is being DataTemplated.
I know how to refer to the currently selected item, by setting the DataContext on a shared ancestor with the ListBox and use {Binding /}. In this example the shared ancestor is a StackPanel. And if the DataContext wasn't explicitly set there I could easily bind to a property on the DatabasesSubFrame object by just doing {Binding SomeProperty}. However, if I do {Binding SomeProperty} within the explicitly set DataContext, it refers to the wrong DataContext.
How do I access the "original" DataContext here? I tried messing with RelativeSources and TemplatedParents but couldn't figure out how to fit them in.
<DataTemplate DataType="{x:Type VM:DatabasesSubFrame}">
<StackPanel DataContext="{Binding Databases}" >
<ListBox Name="DbInfoBox"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding ShortName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Problem: The Command and V:CreateCommandBinding.Command are set incorrectly here. How do I access OpenDbCommand from the top-level DataTemplate's DataContext? -->
<Button Content="Open Database"
CommandParameter="{Binding /}"
Command="{Binding ???, Path=OpenDbCommand.Command}"
V:CreateCommandBinding.Command="{Binding ???, Path=DataContext.OpenDbCommand}"/>
</StackPanel>
</DataTemplate>
I think this question will help you to find the answer to yours. Another trick is to set the Name of the Window to something like "Root". You can then get at the window's original datacontext by using:
{Binding ElementName=Root, Path=DataContext.MyViewModelsProperty}

Categories