I have a view model that has two properties. One of them is myDataGridSelectedItems, that is update in the selection changed event of the datagrid (I am using MVVM light to convert an event to command).
The second property is myText, that is the text that has a textbox in the view.
In my view I have a textBox which text depends on the selection of the dataGrid, if the selection is one item then I put the information of a column of the dataGrid in the textBox, if the selection is 0 or more than 1, then I clear the textBox.
To do that, I use the following code:
<TextBox Height="23" HorizontalAlignment="Stretch" Margin="5,26,0,0" Name="mytextBox" VerticalAlignment="Top"
Text="{Binding ElementName=Principal, Path=DataContext.MyDatagridSelectedItems, Converter={StaticResource TextBoxValueConverter}}">
This works fine because when I select one row in the data grid the textBox has text (the text that the convert returns) and is empty when I select more that one or unselect all rows.
However, in this way the property myText is not update because I don't set the binding, because the binding of the Text property in the axml use the converter, not the property myText of the view model.
So I was wondering if it possible to set two bindings in the Text property of the textBox, or if exists some way to update the myText property in the view model when the text in the TextBox changes.
Thanks.
You are doing it the wrong way around:
Right now, you have view logic encoded in a converter in the view. But view logic is precisly what the view model is there for.
You should have a property for the text of that text box in the view model and bind the text box only to that property.
In the view model you change its value according to the selection.
Related
I've bound a ComboBox to my TextBox
<TextBlock Grid.Row="1" Name="DescriptionText" Text="{Binding ElementName=ScreenLocations, Path=SelectedItem.Description}" />
I have 4 ComboBoxes in my grid. What I want to do is, every time I select an item from any ComboBox, update the TextBox with the selected objects Description property.
Is it possible to bind multiple ComboBoxes to one TextBox, or would I need to use an event of some sort?
Create a property in your ViewModel and bind all your comboboxes' 'selectedItem' property to it (Use Mode="OneWayToSource", this will prevent changes on selectedItem of one ComboBox to affect the other), then bind your TextBox to the same property created in the VM with Mode="OneWay". Don't forget to implement INotifyPropertyChanged in your VM.
I have a MVVM app, which shows a TextBox with its text bound to a viewmodel property:
Text="{Binding Path=Caption, Mode=TwoWay}
The update of 'Caption' property happens only when putting cursor to any other control. Is there a way, a good way, to have the 'Caption' property updated immediately when typing any char? I need this because my app displays a view twice, in same window - one is real 'work area', another - a 'thumbnail', in a listbox of all loaded 'work areas'. 'Work area' would show the new text correctly. A 'thumbnail' updates the textbox only when it loses cursor
For the text property, the default way to update bindings is LostFocus not PropertyChanged, you need to set this explicitly.
Text="{Binding Path=Caption, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}
Source
In my current scenario (WPF, MVVM), I have a user control which hosts a visio diagram. This user control is located on a view, next to a number of labels and a datagrid element.
The user control contains a DependencyProperty object SelectedNode which value is updated with the information received from the Visio diagram. The labels' content are binded so that they display the information contained in the SelectedNode (e.g. id, name):
<Label Grid.Row="1" Grid.Column="1" x:Name="lbNodeIdValue" HorizontalAlignment="Left"
Content="{Binding ElementName=visioControlUC, Path=SelectedNode.Id, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"/>
Every time I change the selection in the diagram, the label's content changes as expected.
Next to this label, I would like to display a datagrid containing information based on the id displayed in the label. This is where I ran into problems, as I can't seem to be able to get the value of the Content property of the label in the viewmodel class.
I have tried using the MultiBinding property on the Content element of the label, and creating a second binding with Mode=OneWayToSource to set the value of the label's Content to a property I have defined in the viewmodel class.
What would be a proper way to retrieve this value in my viewmodel class?
Thanks,
Adrian
Ideally your Datagrid's ViewModel should get the value of the selected label from the other ViewModel. You should not rely on Views to transfer application data between ViewModels.
It sounds like the SelectedNode value originates from the UserControl, and not the ViewModel, so you'll need to bind the UserControl.SelectedNodeId to a ViewModel somewhere so the ViewModels have access to this data
<local:myUserControl x:Name="visioControlUC"
SelectedNode="{Binding SelectedNodeId}" />
If the value is needed by more than one ViewModel, I would highly recommend some kind of event system, such as MVVM Light's Messenger or Prism's EventAggregator. This would allow your ViewModels to subscribe to something like a SelectedNodeChangedEventMessage, and the ViewModel which actually contains the SelectedNodeId can broadcast that message anytime the value changes. You can find an example of both on my blog post about Communication between ViewModels.
I have a WPF Data Grid bound to an observable collection, which is working as intended.
What I am trying to do now is add text below it to say: "Number of selected rows: {count goes here}"
What's the proper way to do this? I could add a new property in the View Model called SelectedCount or something similar and bind to that, but it doesn't feel right. It seems redundant. Also, I could set the label text dynamically in the code behind, but I'm not sure if that's the "right" place to do this either.
Here's an example below.
EDIT:
Please pretend there's a checkbox column header whose intention is to provide check/uncheck all functionality. The state of this header checkbox should not count towards the final count.
You could use element binding to declaratively bind to the SelectedItems.Count property in XAML:
<TextBlock Text="{Binding ElementName=MyDataGrid,
Path=SelectedItems.Count, StringFormat=Number of selected rows: {0}}" />
Update
Presumably you're using MVVM, so adding a SelectedXCount property to your view model is a perfectly reasonable application of the view model. The advantage of having it in the view model is that you could unit test based on the number of selected items. E.g. if you want to check that the user can only progress (a CanNext property returns true) if the user has selected some items.
The SelectedItems property is not a DependencyProperty so can't be bound to, but there are many articles online that get around the issue when using the DataGrid in MVVM. Most of the solutions involve using a mechanism for calling a view model command on the invocation of the DataGrid's SelectionChanged event.
I have a DataGrid which shows a list of type Product. What I want to do is to have a sort of master/detail view where the grid shows the master data, and then a collection of text boxes (etc) shows the detail view. The detail is mainly for large text columns where it is not appropriate to show them in the grid due to the size of the text. There are also some data items that are shown in both the grid and the detail area.
Additionally, I need it so that both the grid and the detail area are bound together, so that a change in either causes the underlying data source to be updated - and if (e.g.) the grid is changed those changes are immediately reflected in the detail area and vice versa.
I think that this can be achieved with binding and dependency properties - but how would I set this up?
Note: as the user can control what columns are displayed on the grid the bindings are defined manually in code..
var column = new DataGridTextColumn()
{
Header = attribute.Name,
Binding = new Binding(attribute.ColumnName) { TargetNullValue = string.Empty },
IsReadOnly = attribute.IsReadOnly
};
dgProductsList.Columns.Add(column);
If you have named the DataGrid all you need to do is bind the DataContext of your details area to the SelectedItem of the grid, all bindings inside the area then will be to the item's properties e.g.
<DataGrid Name="dg" .../>
<Border DataContext="{Binding SelectedItem, ElementName=dg}">
<StackPanel>
<TextBox Text="{Binding SomeTextProperty, UpdateSourceTrigger=PropertyChanged}"/>
<!-- ... -->
</StackPanel>
</Border>
This is two way by default, add UpdateSourceTrigger=PropertyChanged to make the property update immediately, otherwise the text is changed when the focus leaves the TextBox.