Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I've created a custom control for selecting States in my application, called StateSelector. If I place it in my UserControl and bind the ItemsSource (through a custom property called StateList) it works fine. But using the same binding in a DataTemplate does not work.
Here is my StateSelector.xaml
<UserControl x:Class="MyNamespace.StateSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Local="clr-namespace:MyNamespace"
Height="21" Width="60">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Grid.Column="0"
Name="cboState"
SelectedItem="{Binding Path=CurrentState, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
ItemsSource="{Binding Path=StateList, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Code}" />
<TextBlock Text="{Binding Path=Name}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
Here is my StateSelector.xaml.cs
public class StateSelector : UserControl
{
public ObservableCollection<State> StateList
{
get { return (ObservableCollection<State>)GetValue(StateListProperty); }
set { SetValue(StateListProperty, value); }
}
public static readonly DependencyProperty StateListProperty =
DependencyProperty.Register("StateList", typeof(ObservableCollection<State>), typeof(StateSelector));
public State CurrentState
{
get{ return (State)GetValue(CurrentStateProperty); }
set{ SetValue(CurrentStateProperty, value); }
}
public static DependencyProperty CurrentStateProperty =
DependencyProperty.Register("CurrentState", typeof(State), typeof(StateSelector));
/// <summary>
/// Default constructor for StateSelector
/// </summary>
public StateSelector()
{
InitializeComponent();
}
}
Then in the containing UserControl's Constructor I populate an ObservableCollection with State objects.
Here is MyDisplay.xaml.cs
public class MyDisplay : UserControl
{
private static DependencyProperty StateListProperty =
DependencyProperty.Register("StateList", typeof(ObservableCollection<State>), typeof(RateTableDisplay));
public ObservableCollection<State> StateList
{
get{ return (ObservableCollection<State>)GetValue(StateListProperty); }
set{ SetValue(StateListProperty, value); }
}
// Code to define SourceObject as seen in following XAML omitted
public MyDisplay()
{
InitializeComponent();
StateManager stateManager = new StateManager();
StateList = new ObservableCollection<State>(stateManager.GetAll(Context));
}
}
In the XAML of MyDisplay I have a section that uses the StateSelector as is and another that uses it in a DataTemplate.
Here is MyDisplay.xaml
<UserControl x:Class="MyNamespace.MyDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Local="clr-namespace:MyNamespace"
Height="Auto" Width="Auto"
Name="_this"
DataContext="{Binding ElementName=_this, Path=SourceObject}">
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate x:Key="OriginStateCellTemplate">
<Local:StateSelector StateList="{Binding ElementName=_this, Path=StateList}" />
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
<!-- Unrelated XAML omitted -->
<!-- The StateSelector below gets populated properly -->
<StackPanel>
<Local:StateSelector Grid.Column="3" StateList="{Binding ElementName=_this, Path=StateList}" x:Name="cmbMasterOriginState" />
</StackPanel>
<!-- More Unrelated XAML omitted -->
<!-- The StateSelector below does not get populated at all -->
<StackPanel>
<ListView Height="610">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn x:Name="origStateCol" Width="85" CellTemplate="{StaticResource OriginStateCellTemplate}">
<GridViewColumnHeader Click="header_Click" Tag="OriginState">Origin State</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</UserControl>
I've tried different ways to bind the StateList such as these:
StateList="{Binding Path=StateList, Source={x:Reference _this}}"
StateList="{Binding Path=StateList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
But no such luck. I can't figure out why the ItemsSource is not being populated in the DataTemplate example. It works fine outside of the DataTemplate. I'm not getting any binding errors in the Output of Debug in Visual Studio either.
When searching I found quite a few related issues but they all seemed to be trying to use a general DataContext defined in the top UserControl element. I'm specifically trying to use a property of the UserControl itself.
Any ideas?
Implement INotifyPropertyChanged in your UserControl and then create properties for StateList and then on the setter raise the property changed event provided by the INotifyPropertyChanged.
Related
This question already has an answer here:
How to bind a property of one element to a property of another in XAML
(1 answer)
Closed 6 years ago.
Following is my code
<myusrcontrol:settings x:Name="usr1" />
</TabItem>
<TabItem>
<TabItem.Content>
<Grid>
<myusrcontrol:abcselection x:Name="usr2" Height="Auto" />
</Grid>
</TabItem.Content>
</TabItem>
In the above code, I want to disable "usr2" with respect to a CheckBoxControl-Checked Property found in "usr1" through xaml only,
Kindly let me know if there is any solution,
Thanks in Advance
The situation is a little bit more complex than in the post I mentioned as duplicate, so here is a working solution:
As far as I know, you need to create a DependencyProperty (DP) on your UserControl with the Checkbox and bind the Checkbox.IsChecked property to this DP.
Then you can bind your usr2 control on the DP.
Here is the code:
usr1.xaml
<UserControl [...]>
<Grid>
<CheckBox x:Name="MyCheckbox" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:usr1}}, Path=MyCheckboxIsChecked, Mode=TwoWay}" />
</Grid>
</UserControl>
usr1.xaml.cs (code behind)
public partial class usr1: UserControl
{
public usr1()
{
InitializeComponent();
}
public static readonly DependencyProperty MyCheckboxIsCheckedProperty = DependencyProperty.Register(
"MyCheckboxIsChecked", typeof(bool), typeof(usr1), new PropertyMetadata(default(bool)));
public bool MyCheckboxIsChecked
{
get
{
return (bool)GetValue(MyCheckboxIsCheckedProperty);
}
set
{
SetValue(MyCheckboxIsCheckedProperty, value);
}
}
}
usr2.xaml
<UserControl [...]>
<Grid>
<TextBox x:Name="MyTextBox" />
</Grid>
</UserControl>
MainWindow.xaml
<Grid>
<StackPanel>
<local:usr1 x:Name="usr1Control" />
<local:usr2 IsEnabled="{Binding ElementName=usr1Control, Path=MyCheckboxIsChecked}" />
</StackPanel>
</Grid>
I've got an issue binding a code behind string property for a column header. The header is always an empty string when running the application.
<UserControl [...]
DataContext="{Binding RelativeSource={RelativeSource Self}}" >
<c:DataGrid Name="m_dataGrid"
ItemsSource="{Binding Configurations}" >
<c:DataGrid.Columns>
<!-- Column 'Importieren/Exportieren' -->
<c:DataGridTemplateColumn Width="Auto"
MinWidth="100">
<c:DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Name="m_checkBoxExportAllDefinitions"
Content="{Binding ImportExportColumnHeader, Mode=OneWay}"/>
</DataTemplate>
</c:DataGridTemplateColumn.HeaderTemplate>
<c:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsDefinitionExportEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</c:DataGridTemplateColumn.CellTemplate>
</c:DataGridTemplateColumn>
</c:DataGrid>
</UserControl>
As you can see, the DataContext of the UserControl is being set onto itself and the ItemsSource of the data grid is being set to Configurations, which is this code behind property:
public ObservableCollection<ImportExportConfiguration> Configurations { get; private set; }
When setting a break point in the code behind property used to bind the header text (defined in the HeaderTemplate), the getter is never being called:
public string ImportExportColumnHeader {
get {
return IsImport ? ErgaenzungsfelderResources.ImportExportSelectionControlImportierenColumnHeader :
ErgaenzungsfelderResources.ImportExportSelectionControlExportierenColumnHeader;
}
}
The binding for the CellTemplate onto IsDefinitionExportEnabled works. This is a property contained in the ImportExportConfiguration class, whereas ImportExportColumnHeader isn't.
I suppose wpf tries to get the ImportExportColumnHeader property from ImportExportConfiguration where it doesn't exist; that's why it displays an empty header. Is this correct?
How can the code behind property be accessed?
Specifying the correct source solved my issue:
<CheckBox Name="m_checkBoxExportAllDefinitions"
Content="{Binding ImportExportColumnHeader, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type importExport:ImportExportSelectionControl}}}" />
I have a problem with a particular xaml databinding.
I have two listboxes (master-details, so the listboxes have IsSynchronizedWithCurrentItem set to true). I want my viewmodel to know when the selected item on the details listbox changes: I created an int property on my viewmodel class (i.e. we can call this property SelInd)and on the details viewmodel I bind this way:
SelectedIndex="{Binding Mode=OneWayToSource, Path=SelInd}"
I get no errors/exceptions at runtime, but the binding does not trigger: my viewmodel's property does not get updated when the selected item changes. If I change the binding mode to TwoWay everything works fine, but that's not what I need. I need it to work with OneWayToSource (btw the same non-working behaviour applies if I bind SelectedItem to SelectedValue properties).
Why do those bindings do not trigger with OneWayToSource?
Here's a more complete code example, just to get the things clearer:
EDIT: I can't show the real code (NDA) but I'll show here something simpler and similar enough (the Page's DataContext is an instance of the PageViewModel class explained later)
I just need that my viewmodel class's SelInd property should always reflect the value of SelectedIndex in the second ListBox. I have found alternative methods for doing this (Event handler in code-behind or an Attached Behaviour) but right now I'm just curious about WHY it doesn't work with OneWayToSource binding.
<Page>
<ContentControl x:Name="MainDataContext">
<Grid DataContext={Binding Path=Masters}>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding }">
<ListBox.ItemContainerStyle>
...
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
....
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Column="1"
SelectionMode="Single"
SelectedIndex="{Binding Mode=OneWayToSource, ElementName=MainDataContext,Path=DataContext.SelInd}"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Details}">
<ListBox.ItemContainerStyle>
...
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
....
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</ContentControl>
</Page>
Here's a sketch of the view model class
public class PageViewModel{
public ObservableCollection<MasterClass> Masters {get;set;}
public int SelInd {get;set;}
....
}
And here's MasterClass, it just holds a name and a list of details
public class MasterClass{
public ObservableCollection<DetailsClass> Details {get;set;}
public String MasterName {get;set;}
....
}
I think in your case, you must use the mode OneWay. By default, you have used mode TwoWay.
Quote from MSDN about TwoWay:
TwoWay binding causes changes to either the source property or the target property to automatically update the other. This type of binding is appropriate for editable forms or other fully-interactive UI scenarios. Most properties default to OneWay binding, but some dependency properties (typically properties of user-editable controls such as the Text property of TextBox and the IsChecked property of CheckBox) default to TwoWay binding. A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata of the property using GetMetadata and then check the Boolean value of the BindsTwoWayByDefault property.
Mode OneWay, that you need:
OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. This type of binding is appropriate if the control being bound is implicitly read-only. For instance, you may bind to a source such as a stock ticker or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. If there is no need to monitor the changes of the target property, using the OneWay binding mode avoids the overhead of the TwoWay binding mode.
Mode OneWayToSource:
OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changes. One example scenario is if you only need to re-evaluate the source value from the UI.
Below is a diagram for a better understanding of the:
Okay, then I'll show you an example that works for me. Perhaps it will be useful to you.
XAML
<Window x:Class="SelectedIndexHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectedIndexHelp"
Title="MainWindow" Height="350" Width="525"
ContentRendered="Window_ContentRendered"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:SelectedIndexClass x:Key="SelectedIndexClass" />
</Window.Resources>
<Grid DataContext="{StaticResource SelectedIndexClass}">
<ListBox x:Name="MyListBox"
BorderThickness="1"
Width="200" Height="200"
BorderBrush="#CE5E48"
DisplayMemberPath="Name"
Background="AliceBlue"
SelectedIndex="{Binding MySelectedIndex, Mode=OneWayToSource}" />
<Label Name="SelectedIndex" VerticalAlignment="Top"
Content="{Binding MySelectedIndex}"
ContentStringFormat="SelectedIndex: {0}"
Width="100" Height="30" Background="Lavender" />
</Grid>
</Window>
Code behind
public partial class MainWindow : Window
{
public class Person
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
private ObservableCollection<Person> DataForListBox = new ObservableCollection<Person>();
public MainWindow()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
DataForListBox.Add(new Person()
{
Name = "Sam",
Age = 22,
});
DataForListBox.Add(new Person()
{
Name = "Nick",
Age = 21,
});
DataForListBox.Add(new Person()
{
Name = "Cris",
Age = 25,
});
DataForListBox.Add(new Person()
{
Name = "Josh",
Age = 36,
});
DataForListBox.Add(new Person()
{
Name = "Max",
Age = 32,
});
DataForListBox.Add(new Person()
{
Name = "John",
Age = 40,
});
MyListBox.ItemsSource = DataForListBox;
MyListBox.Focus();
}
}
public class SelectedIndexClass
{
private int? mySelectedIndex = 0;
public int? MySelectedIndex
{
get
{
return mySelectedIndex;
}
set
{
mySelectedIndex = value;
}
}
}
Output
In this example, there is a class of data - Person, these data for ListBox. And the class SelectedIndexClass (DataContext), which contains the property MySelectedIndex, which is a parameter of binding OneWayToSource.
Edit: I'm glad you figured out with the problem. I'll try to explain by their example, why are you not working with ElementName case.
So, let's say we have this code:
<ContentControl x:Name="MainDataContext">
<Grid x:Name="MainGrid" DataContext="{StaticResource SelectedIndexClass}">
<ListBox x:Name="MyListBox"
BorderThickness="1"
Width="200" Height="200"
BorderBrush="#CE5E48"
DisplayMemberPath="Name"
Background="AliceBlue"
SelectedIndex="{Binding Path=DataContext.MySelectedIndex, Mode=OneWayToSource, ElementName=MainDataContext}" />
<Label Name="SelectedIndex" VerticalAlignment="Top"
Content="{Binding MySelectedIndex}"
ContentStringFormat="SelectedIndex: {0}"
Width="100" Height="30" Background="Lavender" />
</Grid>
</ContentControl>
As you probably understand, it will not work.
DataContext set on a specific node of the visual tree, all items below (in the visual tree) inherit it. This means that the DataContext will be working since the Grid and below the visual tree. Therefore, the following code will work:
<ContentControl x:Name="MainDataContext">
<Grid x:Name="MainGrid" DataContext="{StaticResource SelectedIndexClass}">
<ListBox x:Name="MyListBox"
BorderThickness="1"
Width="200" Height="200"
BorderBrush="#CE5E48"
DisplayMemberPath="Name"
Background="AliceBlue"
SelectedIndex="{Binding Path=DataContext.MySelectedIndex, Mode=OneWayToSource, ElementName=MainGrid}" />
<Label Name="SelectedIndex" VerticalAlignment="Top"
Content="{Binding MySelectedIndex}"
ContentStringFormat="SelectedIndex: {0}"
Width="100" Height="30" Background="Lavender" />
</Grid>
</ContentControl>
And also, it will work if the name of the point MyListBox. Usually, when set the DataContext, the element name is passed.
Well, I found a way to make it work. I just removed the data-context "indirection" so I don't have to use ElementName in my bindings, and it started working. The working xaml example is:
<Page>
<ContentControl >
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Masters }">
<ListBox.ItemContainerStyle>
...
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
....
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Column="1"
SelectionMode="Single"
SelectedIndex="{Binding Mode=OneWayToSource, Path=SelInd}"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Masters/Details}">
<ListBox.ItemContainerStyle>
...
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
....
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</ContentControl>
</Page>
Now, if someone knows exactly WHY the binding using ElementName does not work, I'd like to know it :)
I have a combo box that is not working as I expect at runtime. I can use the mouse to expand the drop-down window, but clicking an item does not seem to select it. The dropdown goes away, but the selection is not changed. The same control seems to work as expected using the keyboard. Arrow up/down changes the selection. I can use the arrow keys to choose and enter to select to change the value as well.
How do I get clicking to select an item?
<DataTemplate DataType="{x:Type myType}">
<Border ...>
<Grid x:Name="upperLayout">
<Grid x:Name="lowerLayout">
<ComboBox x:Name="combo"
Grid.Column="2"
ItemsSource="{Binding Things}"
SelectedItem="{Binding SelectedThing}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Grid>
</Border>
</DataTemplate>
I can't really tell what's wrong from your code however, I'd strongly suggest you to use Snoop to debug your controls (http://snoopwpf.codeplex.com/)
By holding Ctrl+Shift and pointing the mouse where you ComboBox is supposed to grab the input you would instantly find out who is having the focus instead of your combo box.
You can even change the value of a property, really your best friend for debugging your templates !
EDIT
I'm afraid but the code you've posted works for me:
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication6="clr-namespace:WpfApplication6"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<DataTemplate x:Key="myTemplate" DataType="{x:Type wpfApplication6:MyType}">
<Border>
<Grid x:Name="upperLayout">
<Grid x:Name="lowerLayout">
<ComboBox x:Name="combo"
Grid.Column="0"
ItemsSource="{Binding Path=Things}"
SelectedItem="{Binding Path=SelectedThing}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type wpfApplication6:MyThing}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid x:Name="grid">
<ContentControl x:Name="content" ContentTemplate="{StaticResource myTemplate}" Margin="58,79,71,40" />
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
MyType type = new MyType()
{
Things = new List<MyThing>() {new MyThing() {Name = "aaa"}, new MyThing() {Name = "bbb"}}
};
content.Content = type;
}
}
public class MyType
{
public MyThing SelectedThing { get; set; }
public List<MyThing> Things { get; set; }
}
public class MyThing
{
public string Name { get; set; }
}
Maybe something else is screwing it such as a style with no key or whatever, post more of your code you're having a problem with.
Root cause was that another developer had implemented some code that changed the focus on the preview mouse down event. This code was updated to have the desired behavior without modifying focus and the combo box now works as expected. The information needed to diagnose was not in the original question (can't publish it all...).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Changing the View for a ViewModel
I have a view:
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox ItemSource="{Binding Items}" />
**<???>**
</Grid>
</UserControl>
I have ViewModel:
public class VM
{
// ...
public List<Entities> Items { get; set;}
public String Title { get; set; }
}
and I have a few subview's like this:
<UserControl ...>
<TextBlock Text="{Binding Title}" />
</UserControl>
When user selecta some value from ComboBox in main View, I need to place in second column
of main View some of subViews. If user selects other value in ComboBox, another subView sould replace existing subView.
How can it be done?
I usually just use a ContentControl and let it figure out which view to draw based on DataTemplates
<ContentControl Content="{Binding SelectedView}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<local:ViewB />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelC}">
<local:ViewC />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
You could bind to the SelectedItem of the ComboBox, e.g.
<ComboBox x:Name="cb" ItemSource="{Binding Items}" />
<ContentControl Content="{Binding SelectedItem, ElementName=cb}" Grid.Column="1">
<ContentControl.ContentTemplate>
<DataTemplate>
<v:SubView /> <!-- Bind properties as appropriate -->
<DataTemplate>
<ContentControl.ContentTemplate>
<ContentControl>
If you have differnt views use the ContentTemplateSelector instead of hardcoding one template.