WPF Bind to an ObserVableCollection found inside a dictionary - c#

Hy Everyone!
My situation so far:
I have an observable collection ("PipesSystemList") which is made up of "DataBaseSystem" objects:
public static ObservableCollection<DatabaseSystem> PipesSystemList { get; set; } = new ObservableCollection<DatabaseSystem>();
public class DatabaseSystem
{
public string System { get; set; }
public bool IsChecked { get;set;}
}
I successfully bind this collection to my combobox as it follows and everything works perfectly:
<ComboBox ItemsSource="{Binding ElementName=MainView,Path=DataContext.PipesSystemList}"
Padding="2" Margin="5 0 5 0" Width="70" Height="20"
Foreground ="#F1F1F1" Style="{StaticResource ComboBoxStyleDark}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="local:DatabaseSystem">
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding System}" Foreground="#F1F1F1"
IsChecked="{Binding IsChecked}"
Command="{Binding ElementName=MainView, Path=DataContext.PipeTabChosenSystemChangedCommand }"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
What I wanted to achieve: Because I have multiple equipment type, I wanted to have all the necesarry collection in one place. so I created a dictionary:
var SystemTabLists = new Dictionary<string, ObservableCollection<DatabaseSystem>>()
{
{"Document List",new ObservableCollection<DatabaseSystem>()},
{"Pipes",new ObservableCollection<DatabaseSystem>()},
{"Valves",new ObservableCollection<DatabaseSystem>()},
{"Sensors",new ObservableCollection<DatabaseSystem>()},
{"Vessels",new ObservableCollection<DatabaseSystem>()},
{"Heat Exchangers",new ObservableCollection<DatabaseSystem>()},
{"Filters",new ObservableCollection<DatabaseSystem>()},
{"Other Equipment",new ObservableCollection<DatabaseSystem>()}
};
After this, I tried to bind the combobox to the collection belonging to the Pipes (I successfully managed to fill up the collection with the right elements, so the data I need is there):
<ComboBox ItemsSource="{Binding ElementName=MainView,Path=DataContext.SystemTabLists[Pipes]}"
Padding="2" Margin="5 0 5 0" Width="70" Height="20"
Foreground ="#F1F1F1" Style="{StaticResource ComboBoxStyleDark}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="local:DatabaseSystem">
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding System}" Foreground="#F1F1F1"
IsChecked="{Binding IsChecked}"
Command="{Binding ElementName=MainView, Path=DataContext.PipeTabChosenSystemChangedCommand }"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Unfortunately this is not working.
When I debug the code and I turn on tracing for bindings I receive this:
"BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=DataContext.SystemTabLists[Pipes]"
Could someone help me what am I doing wrong? Or point out if this is not possible to do.
Thanks in advance.

Related

WPF ItemsSource binding show only last item of list

How to show only last item of the list in itemssource binding ?
below is my current code.
xaml
<ItemsControl ItemsSource="{Binding UpgradeTicketStorage}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Width="800">
<TextBlock Text="{Binding TicketTitle}" Style="{StaticResource TicketSelectionSubTitle}" TextAlignment="Left" />
<TextBlock Text="{Binding TicketDescription}" TextWrapping="Wrap" Style="{StaticResource TicketSelectionSubTitle2}" FontSize="19" TextAlignment="Left"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
from class binding i do have added 2 records which is ticketA and ticketB, how can i just display ticketB information ? instead of A and B
class
public class UpgradeTicketDescription : ViewModelBase
{
public string TicketTitle { get; set; }
public string TicketDescription { get; set; }
}
List<UpgradeTicketDescription> _UpgradeTicketStorage;
public List<UpgradeTicketDescription> UpgradeTicketStorage
{
get { return _UpgradeTicketStorage; }
set { _UpgradeTicketStorage = value; OnPropertyChanged("UpgradeTicketStorage"); }
}
UpgradeTicketStorage.Add(new UpgradeTicketDescription { TicketTitle = "TicketA", TicketDescription = "Observation DeckA (Single Ticket)"});
UpgradeTicketStorage.Add(new UpgradeTicketDescription { TicketTitle = "TicketB", TicketDescription = "Observation DeckB (Single Ticket)"});
If you want to bind to a specific item in a list you can go about it by creating a public variable you will bind to. Using what you have provided I've created an example that works for the last item in the list, all I did is create a new variable called LastItem and changed how the binding is in the project. This is just one of many ways of going about this.
xaml
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Width="800">
<TextBlock Text="{Binding LastItem.TicketTitle}" TextAlignment="Left" />
<TextBlock Text="{Binding LastItem.TicketDescription}" TextWrapping="Wrap" FontSize="19" TextAlignment="Left"/>
</StackPanel>
class
public UpgradeTicketDescription LastItem
{
get { return UpgradeTicketStorage.Last(); }
}
This provides this output:

C# Wpf create dynamic check boxes next to one another

Problem
I have a dynamic list of reports gathered from a database, and each of them will have the option to be exported in one of two formats, both, or neither. I would like this to be represented as a list of all reports with two adjacent checkboxes next to one one another (One checkbox for each report format) whose IsEnabled status will be predetermined.
My Current Solution
WPF
<Grid>
<TreeView Name="Views" Grid.Column ="0" ItemsSource="{Binding}" Margin="10,3,30,0" Width="230" MaxHeight="300" Height="244" VerticalAlignment="Top" BorderBrush="White">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="False" ></Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding OC}" >
<CheckBox IsChecked="{Binding CheckedFormat1}" IsEnabled="{Binding EnabledFormat1}" Click="CheckBoxStandardFormat1_Click" Loaded="CheckBoxStandardFormat1_Loaded" Margin="-20,0,0,0">
<CheckBox IsChecked="{Binding CheckedFormat2}" IsEnabled="{Binding EnabledFormat2}" Click="CheckBoxStandardFormat2_Click" Loaded="CheckBoxStandardFormat2_Loaded" >
<TextBlock Text="{Binding Name}" />
</CheckBox>
</CheckBox>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
OC is a data structure of reports which includes information on whether it is enabled for each report type. This code produced the following UI result:
Current Output
However it looks like each instance within the HeirachicalDataTemplate is inheriting the status of IsEnabled from the previous ones, as the greyscale changes.
Does anyone have a better solution which will allow me to bind a dynamic list of reports to a WPF output, with the formatting as described above?
Sorry in advance if this is an easy question, I am really new to C#
Update
The following is a sample of my ViewModel
[PropertyChanged.AddINotifyPropertyChangedInterface]
public class ReportsList
{
public string Name { get; set; }
public bool CheckedFormat1 { get; set; }
public bool CheckedFormat2 { get; set; }
public bool EnabledFormat1 { get; set; }
public bool EnabledFormat2 { get; set; }
public ReportsList()
{
EnabledFormat1 = true;
EnabledFormat2 = true;
}
}
and it's implementation as an ObservableCollection
public ObservableCollection<ReportsList> OC { get; set; }
There appears to be no need to use a TreeView here. You just have a list of reports. Replace TreeView with ListView or ItemsControl and replace HierarchicalDataTemplate with DataTemplate. Rather than nesting the CheckBoxes, use a StackPanel container to hold them together. And the margin of -20 wasn't helping. So you end up with:
<ItemsControl Name="Views" Grid.Column ="0" ItemsSource="{Binding OC}" Margin="10,3,30,0" Width="230" MaxHeight="300" Height="244" VerticalAlignment="Top" BorderBrush="White">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding CheckedFormat1}" IsEnabled="{Binding EnabledFormat1}" Click="CheckBoxStandardFormat1_Click" Loaded="CheckBoxStandardFormat1_Loaded" Margin="20,0,0,0"/>
<CheckBox IsChecked="{Binding CheckedFormat2}" IsEnabled="{Binding EnabledFormat2}" Click="CheckBoxStandardFormat2_Click" Loaded="CheckBoxStandardFormat2_Loaded" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

In UWP I want to get a ListView elements checkboxes's value

So I'm trying to do a program that uses ListView (instead of CheckedListBox), and I want to get the indexes of the checked elements.
I use this as a template for the ListView:
<ListView x:Name="Content" HorizontalAlignment="Left" Height="303" Margin="10,47,0,0" VerticalAlignment="Top" Width="394" ItemClick="Content_ItemClick" SelectionChanged="Content_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Selected}"></CheckBox>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is the data what it got:
public class User
{
public string Name { get; set; }
public bool Selected { get; set; }
}
How could I get back the checked elements index?
I believe your ListView's item source is bound to a backing list
<ListView ItemSource"{x:Bind UserList, Mode=OneWay}" >
<ListItem.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay} Click="Click_Handler"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListItem.ItemTemplate>
</ListView>
The UserList is List<User> which contains all your User.
Since you bind the UserList to the ListView. You could retrieve the selected item by iterating through the list and read the Selected property of each individual User.

Changing the data for a ComboBox in WPF

So I have a ComboBox with data in it and it works how they want:
<ComboBox Grid.Column="1" x:Name="MyComboBox" Margin="2, 0, 2, 0"
ItemsSource="{Binding Path=MySamples}" DisplayMemberPath="SampleName" SelectedValue="{Binding Path=MySample}"
SelectionChanged="OnComboBoxChanged" FontSize="11" FontFamily="Arial"/>
However, now they want the ItemsSource to be indexed. So it should be something like:
some #: SampleName
Is there an easy way to make this change just for the ComboBox drop down without changing the architecture? I cannot change the List itself since in other areas of the map, it's just the SampleName without the index. Thanks.
If your ItemsSource is a complex type:
public class MyClass
{
public int Index { get; set; }
public string Name { get; set; }
}
Then use the DisplayMemberPath property of the ComboBox to control what gets displayed. In this case you'd add:
DisplayMemberPath="SampleName"
to the ComboBox definition.
If instead you want to display both the index and name then you'll need to define an ItemTemplate for the ComboBox:
<ComboBox ....>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Index}" />
<TextBlock Text=" : " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Setting the SelectedItem for ComboBox component in WPF

I have been defined some ComboBox element:
<ComboBox Height="27" Margin="124,0,30,116" Name="cbProductDefaultVatRate" VerticalAlignment="Bottom" ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Label Height="26" Content="{Binding Path=Value}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and set the data source for component items of VatRate type:
private void ShowAllVatRates()
{
cbProductDefaultVatRate.Items.Clear();
cbProductDefaultVatRate.ItemsSource = new VatRateRepository().GetAll();
}
VatRate object has a property:
private Product SelectedProduct
{
get; set;
}
where is a product contains VatRate as well:
SelectedProduct.DefaultVatRate
How to set SelectedItem property of ComboBox to SelectedProduct.DefaultVatRate?
// does not work!!!
cbProductDefaultVatRate.SelectedItem = SelectedProduct.DefaultVatRate;
Thank you for answers!
You need to make sure that the actual object instance behind SelectedProduct.DefaultVatRate is the same instance as the one that is part of the list returned by new VatRateRepository().GetAll() or object.Equals() must return true for the two instances.
Are you looking to get a TwoWay binding like this?
<ComboBox Height="27" Margin="124,0,30,116" Name="cbProductDefaultVatRate" VerticalAlignment="Bottom"
ItemsSource="{Binding}"
SelectedItem="{Binding SelectedProduct.DefaultVatRate, Mode=TwoWay}>
<ComboBox.ItemTemplate>
<DataTemplate>
<Label Height="26" Content="{Binding Path=Value}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Categories

Resources