TextBoxes not synchronized after introducing CollectionViewSource - c#

I'm having trouble with some TextBoxes which are to be synchronized with the current element selected in a ListBox. E.g. I have the following TextBoxes:
<TextBox Style="{StaticResource IdTextboxStyle}" Grid.Row="2" Grid.Column="1" Text="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Style="{StaticResource TextboxStyle}" Grid.Row="3" Grid.Column="1" Text="{Binding Path=CodeName, UpdateSourceTrigger=PropertyChanged}" />
I also have the following ListBox:
<ListBox Name="ListOfAgentsBox" Margin="20, 5, 5, 5" Grid.Row="2" Grid.Column="2" Grid.RowSpan="4"
IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource AgentsViewSource}}"
SelectedIndex="{Binding Path=CurrentIndex, UpdateSourceTrigger=PropertyChanged}">
Which contains the current elements in a collection named Agents, which is a collection of Agent elements.
My problem is, before introducing the following CollectionViewSource:
<CollectionViewSource x:Key="AgentsViewSource"
Source="{StaticResource Agents}">
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="ID" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Everything seemed to work fine - I could click the different elements in the ListBox and edit them just fine in the TextBoxes. However, the TextBoxes and the ListBox are no longer syncrhonized, and I have no idea why.

Related

Binding data to XAML while runtime

I build a Chart with a Grid and some Rectangles, like in this Post:
Drawing a chart in WPF C# design questions
Now I save this Chart to an XAML-File to fill it later by another program.
In this chart I need to bind three Values:
1. Labels
2. MaxHeight - Height (by each bar)
3. Height
My Problem is, that I don't know how to bind it correctly for using it in another application.
The other Application could give me a list or an array with the values and the label, but I dont know how I should bind unknown values to the Rectangles.
In the code below I binded the "ChartLabel" but I need all Chart Labels not only one.
When I creating the chart I don't now how much bars I will have later.
<Grid ShowGridLines="True" Background="#FFF5F5DC" Width="Auto" Margin="5,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Rectangle Fill="#FF0000FF" Grid.Column="{Binding Path=Test6_Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=ChartLabel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" BorderBrush="#00FFFFFF" Background="#00FFFFFF" HorizontalAlignment="Center" Grid.Column="5" Grid.Row="10" />
<Rectangle Fill="#FF0000FF" Grid.Column="{Binding Path=Test7_Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=ChartLabel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" BorderBrush="#00FFFFFF" Background="#00FFFFFF" HorizontalAlignment="Center" Grid.Column="6" Grid.Row="10" />
<Rectangle Fill="#FF0000FF" Grid.Column="{Binding Path=Test8_Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=ChartLabel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" BorderBrush="#00FFFFFF" Background="#00FFFFFF" HorizontalAlignment="Center" Grid.Column="7" Grid.Row="10" />
<Rectangle Fill="#FF0000FF" Grid.Column="{Binding Path=Test9_Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=ChartLabel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" BorderBrush="#00FFFFFF" Background="#00FFFFFF" HorizontalAlignment="Center" Grid.Column="8" Grid.Row="10" />
<Rectangle Fill="#FF0000FF" Grid.Column="{Binding Path=Test10_Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=ChartLabel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" BorderBrush="#00FFFFFF" Background="#00FFFFFF" HorizontalAlignment="Center" Grid.Column="9" Grid.Row="10" />
</Grid>
I'm not sure I follow your description of which part you're having a problem with.
You will have a List.
You want to use a string from that as label and a number as height.
If you iterate that you can find the max and hence calculate some sort of scaling factor so a value of half the max ends up about half the height of your chart.
The way I'd do a series like that is with an itemscontrol. Bind an observablecollection to the itemssource. An itemscontrol has a stackpanel it's contents go in. Make the orientation horizontal and define an itemtemplate. That would have a textblock for the label, (maybe rotated) and a rectangle whose height is bound to your scaled value.
Which is roughly how the terrain visualiser I wrote works.
There are no labels - so this is to give you the idea rather than cut and paste.
<ListBox ItemsSource="{Binding TerrainPointList}"
..
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
A listbox has scrollers and selecteditem. I use selecteditem in mine and that might or might not be useful to you.

How to bind properties of one ObservableCollection of ListView to properties of SelectedItem of another ListView?

So I have a few ListViews. The first is binded to ObservaleCollection<ComPort>. All properties of ComPort may take some predefined values. Other ListViews are responsible for that properties: they show all that possible (predefined) values and SelectedItem should be the current value of that property of ComPort from the first ObservaleCollection.
I can't attach images so here is an external picture, it would make the situation clean: http://i.stack.imgur.com/ZBRRx.png
<Window.Resources>
<ResourceDictionary x:Name="rd">
<l:ComPorts x:Key="vComPorts"/>
<l:SystemPorts x:Key="vSystemPorts"/>
<l:BaudRates x:Key="vBaudRate"/>
<l:Parities x:Key="vParities"/>
<l:DataBits x:Key="vDataBits"/>
<l:StopBits x:Key="vStopBits"/>
<l:Timeouts x:Key="vTimeouts"/>
<l:ComPort x:Key="vSelectedPort"/>
</ResourceDictionary>
</Window.Resources>
...
<ListView
Name="PortsList"
Grid.Row="1"
Grid.Column="0"
Margin="5"
VerticalAlignment="Stretch"
ItemsSource="{StaticResource vComPorts}"
DataContext="{StaticResource vComPorts}"
SelectedValuePath="PortName"
SelectedValue="{Binding ElementName=SystemPortsList, Path=SelectedItem.Value}"
SelectionChanged="PortsList_SelectionChanged"
MouseDoubleClick="PortsList_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox />
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView
x:Name="SystemPortsList"
Margin="5"
VerticalAlignment="Stretch"
DataContext="{Binding Source={StaticResource vSelectedPort}}"
ItemsSource="{Binding Source={StaticResource vSystemPortsView}}"
SelectedItem="{Binding Source={StaticResource vSelectedPort}, Path=PortName}"
MouseEnter="SystemPortsList_Refresh"
MouseLeave="SystemPortsList_Refresh"
Grid.Row="1"
Grid.Column="1" SelectionChanged="SystemPortsList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb" Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</ListView.ItemTemplate>
</ListView>
I've tried to make an instance of class ComPort for saving current value of selected item from the first ListView, but anyway I can't cope with it without help. How this task should be solved?
1) Instead of handling SelectionChanged on the PortsList ListView, bind your checkbox to the ListViewItemsPanel like so:
<CheckBox IsChecked={Binding IsSelected, RelativeSource=Parent/>
2) Add an x:Name to your first ListBox, say x:Name="ComPortLB";
3) Remove DataContext on SystemPortsList;
4) Fix SelectedItem on SystemPortsList like so:
SelectedValue="{Binding ElementName=ComPortLB, Path=SelectedValue.PortName}"
I haven't tested any of this code and I haven't done this kind of stuff for a while, so I apologize for errors, but it should get you closer. I've also had to make some assumptions about your classes since you don't provide enough information.

Dynamic stack of ComboBoxes trying to add new items

I have an Items control bound to a observable collection of TaskActivity objects.
<ItemsControl ItemsSource="{Binding TasksActivities, UpdateSourceTrigger=PropertyChanged}" Margin="20, 0, 20, 20">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="2, 0, 2, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width= "*" />
<ColumnDefinition Width= "*" />
<ColumnDefinition Width= "*" />
<ColumnDefinition Width= "70"/>
</Grid.ColumnDefinitions>
<ComboBox x:Name="test" IsEditable="True" ItemsSource="{Binding Source={StaticResource Locator}, Path=Main.AvailableActivities, Mode=TwoWay}" SelectedValue="{Binding ActivityId}" Text="{Binding Name, UpdateSourceTrigger=LostFocus}" SelectedValuePath="Key" DisplayMemberPath="Value" HorizontalAlignment="Stretch" Grid.Column="0">
</ComboBox>
<TextBox Text="{Binding Length}" Grid.Column="1" />
<TextBox Text="{Binding Comment}" Grid.Column="2" />
<Button Height="24" Content="Remove" HorizontalAlignment="Right" Margin="10, 0, 10, 0" Style="{StaticResource LinkButton}" Grid.Column="3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding Source={StaticResource Locator}, Path=Main.DeleteActivityCommand, Mode=OneWay}" CommandParameter="{Binding Name}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
When a value is typed in the combobox that is doesn't exist and focus is lost, I want to have a prompt appear asking if they want to add add that value to the AvailableActivities list (which is just a Dictionary). Right now the border just goes red, and while it does update the "Name" property of the object inside the OC, it's not real because it can't set the ActivityId since it doesn't actually exist in the list of AvailableActivities.
I've tried an EventToCommand for SelectionChanged and LostFocus, but when a new value is entered, the value I'm returned is 'null' so I can't add it.
Normally I could just bind the text value to a property on the VM and just do it all there, but since it's a property inside a ObservableCollection of TaskActivity objects I'm not sure that's possible.
Any suggestions for achieving this functionality?
First make the ComboBox.Text a two-way binding so that the view model property gets updated:
Text="{Binding Path=Name, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"
With that in place, add a command to the ComboBox's LostFocus event:
<ComboBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<cmd:EventToCommand Command="{Binding Source={StaticResource Locator},
Path=Main.AddNewActivityCommand}"
CommandParameter="{Binding ElementName=test,Path=Text}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
And finally, the "AddNewActivityCommand" should just add the new item (in the "Name" property) to the "AvailableActivities" collection.

Some Sources in one element in WP8

I have an application with mvvm.
In my ViewModel i have 2 ObservableCollection.
One of them binding good like this:
<phone:LongListSelector
Margin="0,0,0,5"
ItemsSource="{Binding ItemSourceMatrix}"
x:Name="LongListSelector_Matrix"
Loaded="Event_LongListSelector_OnLoaded_Matrix"
ItemTemplate="{StaticResource Matrix}"
GridCellSize="20, 20"
LayoutMode="Grid"
FontSize="10"
Padding="10,0,-5,0" Tap="asd"
/>
</phone:PanoramaItem>
But now i need binding to this LongListSelector from another ObservableCollection like this:
<phone:PanoramaItem Header="SE Матрица">
<phone:LongListSelector
Margin="0,0,0,5"
ItemsSource="{Binding ItemSourceMatrix}"
x:Name="LongListSelector_Matrix"
Loaded="Event_LongListSelector_OnLoaded_Matrix"
ItemTemplate="{StaticResource Matrix}"
GridCellSize="20, 20"
LayoutMode="Grid"
FontSize="10"
Padding="10,0,-5,0" Tap="asd"
Background="{Binding Source= ItemSourceMatrixBackground, Path=Colors_Value, Mode=OneWay}"
/>
</phone:PanoramaItem>
But the code (Background="....) above dont work. There are my template:
<!-- Matrix -->
<DataTemplate x:Key="Matrix">
<TextBlock x:Uid="{Binding Matrix_Name}"
Text="{Binding Matrix_Text, Mode=TwoWay}"
FontSize="{Binding Matrix_FontSize}"
Foreground="{Binding Matrix_Foreground}"
/>
</DataTemplate>

DependencyProperty Binding Does Not Update To Collection CurrentItem

I am trying to bind a dependency property to a collection's current selection and for reasons I can't seem to grasp, the binding does not update when the collection changes.
In the example below, I show two example. One is updating correctly (on the textblock/run), and the other only displays the initial element and doesn't change when the data grid selection changes.
<Grid>
<Grid.Resources>
<CollectionViewSource Source="{Binding Path=List}" x:Key="myViewModel"/>
<my:UpdateNotWorking MyObjModel="{Binding Source={StaticResource myViewModel}, Path=CurrentItem}" x:Key="updateNotWorking" />
</Grid.Resources>
<DataGrid ItemsSource="{Binding Source={StaticResource myViewModel}}" Name="mylistbox"/>
<TextBlock TextWrapping="Wrap" FontWeight="Bold" Foreground="#FF50CEFF" FontSize="24" TextAlignment="Center" Height="75">
<Run Text="{Binding Source={StaticResource myViewModel}, Path=text}" Foreground="#FF00E200" />
</TextBlock>
<TextBox Text="{Binding Source={StaticResource updateNotWorking}, Path=MyObjModel.text}" Height="22"/>
</Grid>
My dependency property in this example is "MyObjModel" on the "UpdateNotWorking" dependency object which is instantiated from the xaml code.
I would appreciate any information as to why my property is not updating correctly.
Example Project
Paste this XAML into your MainWindow.
<Grid>
<Grid.Resources>
<CollectionViewSource Source="{Binding Path=List}" x:Key="myViewModel" />
<my:UpdateNotWorking x:Key="updateNotWorking" />
</Grid.Resources>
<DataGrid ItemsSource="{Binding Source={StaticResource myViewModel}}" Name="mylistbox"
SelectedItem="{Binding Source={StaticResource updateNotWorking}, Path=MyObjModel, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock TextWrapping="Wrap" FontWeight="Bold" Foreground="#FF50CEFF" FontSize="24" TextAlignment="Center"
Height="75">
<Run Text="{Binding Source={StaticResource myViewModel}, Path=text}" Foreground="#FF00E200" />
</TextBlock>
<TextBox Text="{Binding Source={StaticResource updateNotWorking}, Path=MyObjModel.text, UpdateSourceTrigger=PropertyChanged}"
Height="22" />
</Grid>
What it is now doing is setting updateNotWorking's MyObjModel property based on the DataGrid's SelectedValue, with UpdatePropertyTrigger set to PropertyChanged to see the changes immediately. No longer do we need to define updateNotWorking's property through the List's CurrentItem because it is not going to change just by selecting it with a DataGrid. You can keep it set, but it is not required as we are doing all the manual labor with the DataGrid SelectedValue.

Categories