I have a ComboBox with a Textblock and a Checkbox displayed to allow me to set a view model boolean property based off the checkbox.
View Code
<ComboBox HorizontalAlignment="Left" IsEditable="True" IsReadOnly="True" Text="-- Filter Columns --">
<ComboBoxItem>
<ComboBoxItem.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Description"/>
<CheckBox IsChecked="{Binding DescriptionHeaderVisibility}"/>
</StackPanel>
</DataTemplate>
</ComboBoxItem.ContentTemplate>
</ComboBoxItem>
</ComboBox>
View Model Property
public bool DescriptionHeaderVisibility
{
get => _descriptionHeaderVisibility;
set => Set(ref _descriptionHeaderVisibility, value);
}
Useful information
I am using MVVM Light
If I do the exact same check box binding somewhere else on the page, it works and notifies my view model of the change.
Binding only does not work within the templated combo box
I am not sure why the binding is not working within the combo box template? Am I just missing something here that I don't know about? If I can get this binding to work properly the plan is to add another few rows of text blocks and check boxes all bound to different boolean properties in my view model.
Picture of drop down box
The problem is, you are using a ContentTemplate, but you do not give it any Content to display. If you just want to use the surrounding DataContext, you could write
<ComboBoxItem Content="{Binding .}">
Inspired by this answer to a similar question.
Related
I have two devexpress gridcolumns with one radio button in each.
In code behind when I am setting a value to the properties binding to the radio button, the binding takes. But when I am changing selected radio button in the view the selected won't trigger the property.
what am I missing?
<dxg:GridColumn Binding="{Binding IsOrder}"
Header="Order"
Visible="{Binding IsVisible}"
Width="60">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Path=Value, Mode=TwoWay}"
GroupName="{Binding RowData.Row.Number}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
IsEnabled="{Binding
Path=View.DataContext.StatusNotHandled}"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
<dxg:GridColumn Binding="{Binding IsNotOrder}"
Header="Not order"
Visible="{Binding IsVisible}"
Width="60">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Path=Value, Mode=TwoWay}"
GroupName="{Binding RowData.Row.Number}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
IsEnabled="{Binding
Path=View.DataContext.StatusNotHandled}"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
The cause of your problem is most likely the fact that you are trying to use a non-DX control as an edit of a GridColumn which is discouraged explicitly by DevExpress. Try replacing the RadioButton with a DX-CheckEdit for example.
Key-take-aways from my experience:
do NOT use non-DX controls as InplaceEdits of a GridControl.
for DX-edits to work correctly when assigned in a CellTemplate
their name has to be set to 'PART_Editor'. Omitting that will lead to problems with navigation etc.
Use the the GridColumn.FieldName-property instead of binding. This should make the InplaceEdit inherit the binding from its Column automatically.
Change your binding for IsChecked to RowData.Row.IsOrder, it will probably solve your selection problem. You can read a little bit more information on using RowData.Row over Value or Data here.
On another note, as #Sancho Panza said, you're always better to stick with BaseEdit descendant when dealing with CellTemplate.
This is one of the advantages of using a BaseEdit descendant in CellTemplate :
For the DevExpress Data Editors (the BaseEdit class's descendants), you can set the editor's Name property to PART_Editor. In this case, the GridControl automatically adjusts its appearance and synchronizes the editor with the source field specified by the ColumnBase.FieldName or ColumnBase.Binding properties.
You can use any binding with an editor named PART_Editor. In this case, the GridControl's logic of getting/setting the editor's value is disabled.
The final decision of using a BaseEdit descendant or a WPF RadioButton is yours, but I also recommend sticking with BaseEdit.
I have a list of check boxes and a single check box that acts as CheckAll/UncheckAll for all items in the listbox.
How can I make the chkAll Check Box checked if all the items are checked in the listbox binding ?
I could create a property in the view model to achieve that. I would like to do it in the xaml code.
<ListBox Name="listBox" ItemsSource="{Binding mySource}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelectedProperty}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Name="chkAll" Content="CheckAll/UnCheckAll" IsChecked ={}/>
I think you will need to have a higher-level view model property that reflects this additional state. The state has three possible values too, so be sure to set IsThreeState to true, and bind it to a Nullable<bool>.
Then in this property's setter, you can update all the other checkbox properties.
For each item's IsSelectedProperty, you'll need to update the three-state property too.
In our application we have a screen design feature which is comprised of a custom ScreenDesignPanel and a Property Grid with a ComboBox at the top which points to the selected item on the ScreenDesignPanel. This allows the user to select the UIElement via the ComboBox or via the mouse to set its properties. We achieve this by binding the ItemsSource of the ComboBox to the ScreenDesignPanel's Children collection, then binding their SelectedItems together. This works great.
However, for whatever reason, if the SelectedItem is a ContentControl or a subclass like Button the ItemTemplate specified for the ComboBox is ignored for the 'selected item area' but it is applied when displaying the item in the dropdown list. If the SelectedItem is not a ContentControl, the template is used in both cases.
This also is seemingly specific to the ComboBox. If we use any other selector control: ListBox, ListView, ItemsControl... even third-party ComboBox controls... they all work as expected, properly applying the DataTemplate. ComboBox is doing something internally which no other control is doing.
Note: Below is an over-simplified example for illustrative purposes of the issue only. It is not how we're actually using it as described above.
Also of note: In the DataTemplate for the ComboBox.ItemTemplate, we are only using properties (i.e. Foreground in the example), and are not displaying the DataContext (i.e. the actual ContentControl) itself. This is important because again, the actual control already exists on the ScreenDesignPanel and therefore can't be used for display in the ComboBox's ItemTemplate as it would have two parents which isn't allowed. In other words, it is being used purely as data here.
One last thing... we have a working solution in our app, which was to wrap the Children before binding it to the ComboBox.ItemsSource. However, I'm still curious as to why the ComboBox behaves the way it does which is SPECIFICALLY what I'm asking. (In other words, I'm not looking for other solutions to this design. We already have a working one. I'm looking for clarity on the odd behavior of the ComboBox itself.)
On to the code!
In the first example below, note how the data template is applied to everything in the dropdown, but the selected item area only uses a template if the selected item is not a ContentControl.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="I am the template" Foreground="{Binding Foreground}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<!-- Four 'Data' items for example only -->
<TextBlock Text="I am a Red TextBox" Foreground="Red"/>
<ListBox Foreground="Purple">
<ListBoxItem>I am a Purple ListBox</ListBoxItem>
</ListBox>
<ContentControl Content="I am a Blue ContentControl" Foreground="Blue" />
<Button Content="I am a Button with Green text" Foreground="Green" />
</ComboBox>
This second example shows that it is completely acceptable and fully supported to use a UIElement as the content of a ContentPresenter and still use a DataTemplate (via ContentTemplate) so you can use it in a purely-data role, allowing the template itself to define the visual appearance without displaying the UIElement itself, which is used purely as data here.
<ContentPresenter>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Text="I am the ContentTemplate" Foreground="{Binding Foreground}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
<ContentPresenter.Content>
<Button Content="I am the button" Foreground="Green" />
</ContentPresenter.Content>
</ContentPresenter>
Again, the issue is specific to a ComboBox. I want to find out why the data template isn't applied in that single case, and how to force it to be applied, if possible.
Of note, ComboBox does define SelectionBoxItemTemplate which is separate from the regular ItemTemplate but the rub is that is read-only so you can't set it. We really don't want to re-template the ComboBox as that can mess up proper theming.
Have you tried explicitly setting the DataTemplate to the ContentControl.ContentTemplate property?:
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate">
<TextBlock Text="{Binding Content,
StringFormat='Displayed via template: {0}'}" />
</DataTemplate>
</UserControl.Resources>
...
<ContentControl Content="ContentControl"
ContentTemplate="{StaticResource DataTemplate}" />
EDIT:
The Answer I was looking for was....
<dataFormToolkit:DataField Label="Business Type:">
<ComboBox x:Name="BusinessType" SelectedItem="{Binding BusinessType, Mode=TwoWay}" >
<ComboBox.Items>
<sys:String>Land</sys:String>
<sys:String>Maritime</sys:String>
</ComboBox.Items>
</ComboBox>
</dataFormToolkit:DataField>
Heres the link to the article
I have a c# silverlight business application that uses the ado.net entity framework and the domain service class to bind to my sql server database and pull data from/ persist data to my database. I have been using the dataformtoolkit namespace to layout textboxes which can be edited/display data, using a TwoWay binding mode in order to allow the read/write functionality.
On some of the fields I want to use a combobox instead of a textbox in order to add a better user experience to my application. The impression i've got from reading around the web is that this isnt as easy as it should be.
My current textbox code looks like:
<dataFormToolkit:DataField>
<TextBox Text="{Binding BusinessType, Mode=TwoWay}" />
</dataFormToolkit:DataField>
my attempt at something similar is as follows but incorrect:
<ComboBox>
<ComboBox.Items>
<ComboBoxItem Content="Maritime" IsSelected="{Binding BusinessType, Mode=TwoWay}" />
<ComboBoxItem Content="Land" IsSelected="{Binding BusinessType, Mode=TwoWay}" />
</ComboBox.Items>
</ComboBox>
NB/ I want the combobox to be populated by a list or an enum etc. (preferably a list). The contents of the combobox should have nothing to do with the database, just that when the user hits submit the selection made in the combobox gets persisted back to the database. It is also important that the combobox can read from the database and display the specific selection that has already been made if this is the case.
****EDIT:
Current setup of dataform bound to datagrid with editable businesstype field as a textbox (I want to replace this textbox with a combobox that has two selectable items).
<!--DataForm Declaration-->
<dataFormToolkit:DataForm x:Name="dataForm1" Height="410" Width="331"
VerticalAlignment="Top"
Header="Job Details"
CurrentItem="{Binding SelectedItem, ElementName=dataGrid1}"
HorizontalAlignment="Left" >
<dataFormToolkit:DataForm.EditTemplate>
<DataTemplate>
<StackPanel>
<dataFormToolkit:DataField>
<TextBox Text="{Binding BusinessType, Mode=TwoWay}" />
</dataFormToolkit:DataField>
</StackPanel>
</DataTemplate>
</dataFormToolkit:DataForm.EditTemplate>
</dataFormToolkit:DataForm>
So how do i manipulate this code to use a combobox instead of a textbox?
Any help in doing this would be greatly appreciated.
You should setup your binding to use the ComboBox's SelectedValue property.
<ComboBox SelectedValue="{Binding BusinessType, Mode=TwoWay}">...</ComboBox>
The problem with this is that the ListBox and ComboBox will use the Equals() method on the object in the SelectedItem so if the types do not match then the ComboBox will not set the appropriate item as selected. Therefore, BusinessType will need to be a string since you are using ComboBoxItem's and specifying string content.
If bound the ItemsSource of the ComboBox then you would use SelectedItem and it would actually be an entity type as well, in which case you have more flexability/control around what equals what.
I have a ComboBox in WPF which is databound, and has data template which controls how each of the items is displayed. I have made it so that each item is displayed with two bits of text (for the Name and Path properties) and one image (for the Icon property).
At the moment when I select an item from the ComboBox the textbox bit of the ComboBox just changes to say "TestWPF.Result" which is the name of the class which I have populated the ComboBox with.
I'm interested in one (or both) of two things:
How do I change it so that it displays the value of one of the fields there (eg. so it shows the value of the Name field rather than the name of the class)?
Is it possible get it to use the same DataTemplate there as in the list of items, so that once I have selected an item it displays in the closed ComboBox the same way as it looks in the list of items. Basically I've got a DataTemplate called ShowResults and a ComboBox which uses that template. I've also added in a separate ContentControl which I've got to show the details of the selected item in the ComboBox, but I want to get that to replace the textbox in the ComboBox.
Update:
Thanks for the first answer. I've tried using a separate ContentControl, as you've described, and it works fine. The question now is how to replace the textbox part of the ComboBox with this ContentControl. Any hints on that would be most welcome.
Also, is it possible to replace the textbox bit of the ComboBox control with a mixture of the ContentControl and a textbox, so that I can still type in the textbox to help select items from the ComboBox, but then when I close the dropdown the rest ContentControl bit will be populated with the rest of the text and the icon. Hope that makes sense - ask questions if it doesn't!
Code:
I've been asked to post my code - so here it is. I've tried to remove things that I know are definitely not relevant, but I'm not sure exactly what is relevant so when in doubt I've left things in.
<Window x:Class="TestWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:TestWPF"
Title="Window1" Height="300" Width="843" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="ShowResult" DataType="TestWPF.Result">
<StackPanel Margin="5" Orientation="Horizontal">
<Image Width="32" Height="32" Source="{Binding Path=Image}"/>
<StackPanel Margin="5">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Path}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid Width="786">
<Button Height="23" HorizontalAlignment="Right" Margin="0,24,166,0" Name="btnTest" VerticalAlignment="Top" Width="75" Click="btnTest_Click">Add</Button>
<ComboBox StaysOpenOnEdit="True" DropDownClosed="comboBox1_DropDownClosed" PreviewTextInput="comboBox1_PreviewTextInput" SelectionChanged="comboBox1_SelectionChanged" ItemTemplate="{StaticResource ShowResult}" Margin="259,109,22,89" Name="comboBox1" IsEditable="True" />
<ContentControl Height="50" Margin="268,0,22,21" Name="contentControl1" VerticalAlignment="Bottom" Content="{Binding ElementName=comboBox1,Path=SelectedValue}" ContentTemplate="{StaticResource ShowResult}"/>
</Grid>
You got the binding part right - binding to the data and using a DataTemplate to display the source the way you want to.
As to your second question, a way to do it would be to use a ComboBox with IsEditable="True" as you have, and withing the TextChanged event handler check if the comboBox.Items contains the new value, if not check use Linq to seach for a match:
if (comboBox.Items.Contains(e.NewValue))
return;
var matches =
with comboBox.Items
select item
where item.BeginsWith(e.NewValue);
if (matches.Count > 0)
comboBox.SelectedItem = matches.First();
Just place the Property Binding expression to the textBox,You dont need to apply template.
Another way to get exact Data template, Place a ContentControl in the place of textBox and assign the same DataTemplate (say x:Name="robinTemplate")
<ContentControl Content="{Binding ElementName=cmbBox,Path=SelectedValue}" ContentTemplate="{StaticResource robinTemplate}"/>
For making the Selected content display in the same way :
Create a copy of the combobox control template and you will find a ContentPresenter there. Replace that with the ContentControl.. This is not the right solution though.