Reputation: 417
I'm using the WPF combobox for filtering the items but I decide to put it in my datagrid instead but i can't get it to work probably in their i can only get it to work when is outside of the datagrid.
I think the problem is because
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, or ElementName=win
isn't supported inside the datagrid so how do I getting it to work.
this is the error I get
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=SelectedParam; DataItem=null; target element is 'ComboBox' (Name='Krydsmålbox'); target property is 'SelectedValue' (type 'Object')
<DataGrid x:Name="hjuldata"
ItemsSource="{Binding Source={StaticResource cvsTasks}}"
CanUserAddRows="False" BorderBrush="#FF303030" Foreground="#FF00FB0B" Background="#FF303030" AutoGenerateColumns="False" GridLinesVisibility="None" VerticalAlignment="Center" Height="644" Canvas.Left="20" Canvas.Top="257" Width="1250" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Krydsmålet}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
<DataGridTextColumn.Header>
<ComboBox x:Name="Krydsmålbox" Foreground="#FFEAEAEA" Background="#FF303030" FontSize="12"
Style="{StaticResource ComboBoxTest2}" ItemTemplate="{StaticResource cmbTemplate2}"
ItemsSource="{Binding}" SelectedValuePath="Krydsmålene"
SelectedValue = "{Binding SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}" BorderBrush="#FF303030" Height="40" DockPanel.Dock="Top" IsSynchronizedWithCurrentItem="True" SelectionChanged="Krydsmålbox_SelectionChanged" Canvas.Left="813" Canvas.Top="96" Width="146"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
data template
<DataTemplate x:Key="cmbTemplate2">
<WrapPanel Margin="0 5 0 5" Height="30">
<Image Width="10" Height="20" Stretch="Fill" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,15,0"/>
<Label Content="{Binding Krydsmålene}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16" Foreground="#FF00FB0B"/>
</WrapPanel>
</DataTemplate>
CS
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string SelectedParam
{
get { return _selectedParam; }
set
{
_selectedParam = value; OnPropertyChanged("SelectedParam");
if (_selectedParam == "Krydsmål") { BindData(); } else { hjuldata.ItemsSource = FilterKategori().Tables[0].DefaultView; ; }
}
}
public DataSet DTbindkryds()
{
Data = @"SELECT Krydsmålene FROM Data.Krydsmål";
//SQL statement to fetch entries from Krydsmål
DataSet dsdata = new DataSet();
//Open SQL Connection
using (conn = new SqlConnection(connStrings))
{
conn.Open();
//Initialize command object
using (conn = new SqlConnection(connStrings))
using (cmd = new SqlCommand(Data, conn))
{
SqlDataAdapter adapters = new SqlDataAdapter(cmd);
//Fill the result set
adapters.Fill(dsdata);
conn.Close();
}
}
return dsdata;
}
private void bindkrydsmål()
{
Krydsmålbox.ItemsSource = DTbindkryds().Tables[0].DefaultView;
}
Upvotes: 3
Views: 714
Reputation: 8803
I think your real problem is very small and frequent with WPF
developers. Change your SelectedValue
binding like below:
SelectedValue = "{Binding DataContext.SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}"
As you have not given the code how you are assigning the DataContext
for window
, it's a viable option to check for. If it's the same window
class then binding should work without DataContext.
but the assumption that RelativeSource
binding is not supported inside the datagrid
is wrong. RelativeSource
will work as long as element is in VisualTree
of control and your combo box is in visualtree of window. Right?
To save time on proving the fact, below is the demo (created by using maximum of your code reuse and using template in header of DataGrid
).
XAML:
<DataGrid ItemsSource="{Binding Items}" CanUserAddRows="False" AutoGenerateColumns="False" VerticalAlignment="Stretch" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding DeviceState}">
<DataGridTextColumn.Header>
<ComboBox HorizontalAlignment="Stretch" Width="200" SelectedValuePath="DeviceState"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.Items}"
SelectedValue = "{Binding SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding DeviceState}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="200"/>
</DataGrid.Columns>
</DataGrid>
Code Behind:
public MainWindow()
{
Items = new List<Device>();
Items.Add(new Device() { Name = "Device1",DeviceState = 1 });
Items.Add(new Device() { Name = "Device2", DeviceState = 2 });
Items.Add(new Device() { Name = "Device3", DeviceState = 3 });
Items.Add(new Device() { Name = "Device4", DeviceState = 4 });
Items.Add(new Device() { Name = "Device5", DeviceState = 5 });
InitializeComponent();
}
public List<Device> Items { get; set; }
private string _selectedParam = "1";
public string SelectedParam
{
get { return _selectedParam; }
set
{
_selectedParam = value;
UpdateProperty("SelectedParam");
}
}
Output:
As you can see in output that is a combobox
in header of datagrid
has a selected item by default and that is reflected using relativesource
binding as you can see in above XAML
.
Upvotes: 0
Reputation: 8243
Don't use a DataTemplate in the Header
property, use it in the HeaderTemplate
like so:
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<ComboBox x:Name="Krydsmålbox" Foreground="#FFEAEAEA" Background="#FF303030" FontSize="12"
Style="{StaticResource ComboBoxTest2}" ItemTemplate="{StaticResource cmbTemplate2}"
ItemsSource="{Binding}" SelectedValuePath="Krydsmålene"
SelectedValue = "{Binding SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}" BorderBrush="#FF303030" Height="40" DockPanel.Dock="Top" IsSynchronizedWithCurrentItem="True" SelectionChanged="Krydsmålbox_SelectionChanged" Canvas.Left="813" Canvas.Top="96" Width="146"/>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
Once you do so, both ElementName
and RelativeSource
should work.
If you want to be able to refer to the combobox by name in the code behind, you can use a ContentPresenter
to present whatever kind of Header you want (I think the default HeaderTemplate is a TextBlock instead of a ContentPresenter):
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
<DataGridTextColumn.Header>
<ComboBox x:Name="Krydsmålbox" Foreground="#FFEAEAEA" Background="#FF303030" FontSize="12"
Style="{StaticResource ComboBoxTest2}" ItemTemplate="{StaticResource cmbTemplate2}"
ItemsSource="{Binding}" SelectedValuePath="Krydsmålene"
SelectedValue = "{Binding SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}" BorderBrush="#FF303030" Height="40" DockPanel.Dock="Top" IsSynchronizedWithCurrentItem="True" SelectionChanged="Krydsmålbox_SelectionChanged" Canvas.Left="813" Canvas.Top="96" Width="146"/>
</DataGridTextColumn.Header>
Upvotes: 4