DevExpress GridControl ComboBoxEdit list item context menu command binding - binding

I have this DevExpress GridControl that is dynamically created using a CellTemplateSelector. One of the GridControl columns is defined by a DataTemplate that appears as follows:
<DataTemplate x:Key="NameComboColumnTemplate">
<ContentControl>
<dxg:GridColumn
x:Name="GridColumnName"
FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
Header="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Header, RelativeSource={RelativeSource Self}}"
Width="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Width, RelativeSource={RelativeSource Self}}">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<dxe:ComboBoxEdit
IsTextEditable="False"
SelectedItem="{Binding RowData.Row.SelectedCylinderName, Mode=TwoWay}"
ItemsSource="{Binding RowData.Row.NameList, Mode=TwoWay}">
<dxe:ComboBoxEdit.ItemContainerStyle>
<Style TargetType="dxe:ComboBoxEditItem">
<Setter Property="dxb:BarManager.DXContextMenu">
<Setter.Value>
<dxb:PopupMenu>
<dxb:BarButtonItem
x:Name="BarButtonItemName"
Content="Delete"
Command="{Binding DeleteNameCommand}"
CommandParameter="{Binding}"/>
</dxb:PopupMenu>
</Setter.Value>
</Setter>
</Style>
</dxe:ComboBoxEdit.ItemContainerStyle>
</dxe:ComboBoxEdit>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
</ContentControl>
</DataTemplate>
There exists a class called DataGridRow, that contains properties for ONE row of GridControl data. This class also contains a command defined as
public ICommand DeleteNameCommand => new DelegateCommand<object>(obj => DeleteName(obj));
private void DeleteName(object obj)
{
// the obj parametercontains the text present on the ComboBoxEdit list item that was
// right-clicked to display the context menu.
// Delete the name from the list here
}
As shown above, the ComboBoxEdit SelectedItem and ItemsSource properties are bound to DataGridRow properties accessed via the RowData.Row property, and the DeleteNameCommand is also accessible via the RowData.Row property.
When the user clicks the ComboBoxEdit down-arrow, the list of Names is displayed, and when the user right-clicks a list name, the context menu is displayed. Since the PopupMenu/BarButtonItem is not part of the Visual Tree, how would I bind the BarButtonItem Command property to the RowData.Row property accessed in the ComboBoxEdit? ... and how could I pass the text of the ComboBoxEdit list item that was right-clicked as the value of the CommandParameter?
Any pointers to the right direction are very much appreciated.

OK ... after days of trying to figure this out, the great people at DevExpress were able to provide me with a solution. My apologies for posting the question as I did not expect (my bad) to get a solution so quickly (I asked them yesterday afternoon), but I thought it useful to inform the community of the solution.
The ComboBoxEdit editor data context is accessible via
(dxe:BaseEdit.OwnerEdit).DataContext
and to access the associated RowData.Row property, which itself contains the properties usable for each row column, is accessible via
(dxe:BaseEdit.OwnerEdit).DataContext.RowData.Row
SO, it follows that the PopupMenu/BarButtonItem Command can be bound to the DeleteNameCommand contained in the DataGridRow class, which itself is accessible via RowData.Row by specifying the following:
Command="{Binding Path=(dxe:BaseEdit.OwnerEdit).DataContext.RowData.Row.DeleteNameCommand, RelativeSource={RelativeSource Self}}"
... and the text of the ComboBoxEdit list item that was right-clicked is available to pass as the value for CommandParameter via the following declaration:
CommandParameter="{Binding}"
... and there was much rejoicing :-)

Related

XUL get the value of MENUITEM selected

I am creating a dropdown in XUL like this:
<button id="bid" oncommand="alert(event.target.nodeName)" >
<menupopup>
<menuitem label="one" value="one" />
<menuitem label="two" value="two" />
<menuitem label="three" value="three" />
</menupopup>
</button>
I want to alert the value of nodeitem which is being clicked. Using event.target.nodeName giving nodeName as menuitem but using nodeValue is retuning undefined as it starts to take value of button node. How can I get the value of the menuitem clicked. I also tried $(this).val() but even that gave undefined. Using $(this).attr('value')
also didn't help. I can put oncommand for menuitem but that doesn't seem to be actual solution. Is that the only way or some method exist to get the value?
The XUL code you have in the question is non-functional. Either you should be using a <menulist> instead of a <button>, or your <button> needs the property type="menu" or type="menu-button". If you are going to use a <button> without the type="menu" property, you would actually have to open a popup in the command event handler for the <button> and then select from there. That does not appear to be what you are wanting. It is, however, quite doable. I use a construction like that in one of my add-ons, except I have it open when one of several <label> items is clicked. This allows re-use of a single <menupopup> for multiple different items in the window. In that case, the <menupopup> is a rather large amount XUL code that I did not want to repeat and maintain multiple duplicates in the XUL for the window.
The value of the <menuitem> selected:
Your actual question is how to get the value of the <menuitem> selected by the user. All of the code below is tested and functional. As you can see from the code you can get the value of the <menuitem> you select (at the time of selection) from: event.target.value.
Using a <menulist> element:
The most common element to use would be a <menulist>. This would normally be used when you are having the user select from multiple options a choice that is going to be remembered and used later, or used to adjust what is presented in the user interface. It would generally not be used to select from multiple immediate actions (which are acted upon and the choice not remembered). A <menulist> is what is used in the examples for <menuitem> and <menupopup> on MDN.
<menulist id="bid2" oncommand="alert(event.target.value)" >
<menupopup>
<menuitem label="one" value="one" />
<menuitem label="two" value="two" />
<menuitem label="three" value="three" />
</menupopup>
</menulist>
The above code will give you what looks like a button with a selection of <menuitem> entries when you click on it. It will alert with the value of the <menuitem> you have selected.
This will produce an item that looks like:
Which you can click on to open a drop-down list:
If you select an item:
You will get an alert:
And the object will then show your selection:
Using a <button> element:
It is also possible to use a <button> element with the property type="menu" or type="menu-button" specified. However, this provides no visual feedback to the user as to which option is currently selected. [Note: Your JavaScript could manually change the <button> label property to provide this feedback.] You could use this type of element if it is button that produces an immediate action rather than a selection that is remembered.
The code:
<button type="menu" id="bid2" label="A Button" oncommand="alert(event.target.value)">
<menupopup>
<menuitem label="one" value="one" />
<menuitem label="two" value="two" />
<menuitem label="three" value="three" />
</menupopup>
</button>
This will produce an item that looks like:
Which you can click on to open a drop-down list:
If you select an item:
You will get an alert:
And the object will then NOT show your selection:
If you want to set the label of the <button> to reflect the selection made by the user, you could use:
<button type="menu" id="bid2" label="A Button" oncommand="event.target.parentElement.parentElement.label=event.target.value;alert(event.target.value)">
<menupopup>
<menuitem label="one" value="one" />
<menuitem label="two" value="two" />
<menuitem label="three" value="three" />
</menupopup>
</button>
When three is selected, that will result in a button that looks like:
Using a <toolbarbutton>:
You could, alternately, use a <toolbarbutton>.
When not hovered, doing so would look like:
When hovered:
When open for selection:
Choices in UI design:
There are many choices that you have to make when designing your user interface. There are many different ways to get to the same effective result, with somewhat different look and feel. You really should be trying these types of options on your own. You may find the XULRunner program XUL Explorer to be of use when prototyping XUL.
Selecting UI elements and a look and feel is, in my opinion, beyond the scope of questions on stackoverflow. While you probably won't get specific XUL help, you can ask UI design questions at: the User Experience stack exchange.

Windows Phone Binding

In my RoomView.xaml I have:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox ItemsSource="{Binding myStrings, Mode=TwoWay}"></ListBox>
</Grid>
In my constructor I am doing:
var myStrings = new List<string>{"Usmaan","Carl","Andy","Saul"};
DataContext = myStrings;
Yet nothing is being spat out on the page when I load the application.
Can anyone see where I am going horribly wrong?
The DataContext of your page is already set to the List object, so you just need to set the binding like this:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox ItemsSource="{Binding, Mode=TwoWay}"></ListBox>
</Grid>
Alternatively, you could create an object that has a MyStrings property and use it as the DataContext of the page. Then you could bind the ListBox like you did {Binding myStrings, Mode=TwoWay} while also being able to bind other controls to other properties of that object (that's the principle of ViewModels).

How to simplify assigning the same converter to multiple bindings (windows store app)?

<TextBlock Visibility="{Binding IsTrue1, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Visibility="{Binding IsTrue2, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Visibility="{Binding IsTrue3, Converter={StaticResource BooleanToVisibilityConverter}}"/>
The "Converter" Property is on Binding, not on TextBlock, so I can't use a style on TextBlock.
Each binding is different, so I can't create a single Binding resource.
So, how to avoid setting the same converter 3 times?
EDIT: I'll try to explain a bit more. What I'm looking for is a way to give the binding object a default converter, so that I don't have to set the same converter over and over again when I create many bindings with the same converter.
So if I can write sth like:
<Grid DefaultBindingConverter="{StaticResource BooleanToVisibilityConverter}">
<TextBlock Visibility="{Binding IsTrue1}"/>
<TextBlock Visibility="{Binding IsTrue2}"/>
<TextBlock Visibility="{Binding IsTrue3}"/>
...
Clearly this is not correct, just to illustrate my idea.
Hope this time I explained it clear enough.
Let's touch about two issues in your question.
1. Single Resource
It seems that you are misunderstood about the StaticResource definition in Converter.
The BooleanToVisibility that you've coded, for example, is worked not three-times-copied object. It only declared once and used three times.
Let's take another example, if you code as below
int i;
i=1;
i=2;
i=3;
You declared i once, and used it three times. Likewise, StaticResource that you used are works as similar. You may declare x:Key="BooleanToVisibility" in <UserControl.Resources> or <Application.Resources> tag, that's it.
2. Style usage
If you want to set Style in TextBlock, you may use below approach.
<TextBlock Visibility="{Binding Number1, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock.Style>
<Style>
<!-- Define your Styles here -->
</Style>
</TextBlock.Style>
<TextBlock>
As you can see above, You can expand Style XAML attribute into inner tag.
==EDIT==
I now understand your intention. You probably want to apply Converter in a hierarchical inheritance manner like a DataContext works.
Sadly, as far as I know, that is NOT possible under XAML. Because each Binding is just a property so that it has to be applied one-by-one.
Possible workaround is to use code-behind to enumerate elements and apply them.
for(int i=0;i<3;i++){
var textbox = (TextBox)this.FindName("TextBox" + i);
var binding = new Binding("IsTrue" + i);
binding.Converter = new YourDefaultConverter();
textbox.SetBinding(TextBox.TextProperty, binding);
}
hope this helps to reduce your chores.

How to binding to relative source

Do you see any problem with my codes when I tried to bind a check box inside a DataGrid to a public property of a the View Model which is the data context of the user control.
thanks,
Jdang
<Custom:DataGrid ItemsSource="{Binding Customers}"
AlternatingRowBackground="AliceBlue"
AutoGenerateColumns="False"
MaxHeight="250"
CanUserAddRows="False"
CanUserDeleteRows="False" >
<Custom:DataGrid.Columns>
<Custom:DataGridTemplateColumn>
<Custom:DataGridTemplateColumn.Header>
<WrapPanel>
<CheckBox IsChecked="{Binding Path=IsCheckAll, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},
UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock>Select<LineBreak/>UnSelect</TextBlock>
</WrapPanel>
</Custom:DataGridTemplateColumn.Header>
<Custom:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Selected, Mode=TwoWay}"/>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellTemplate>
</Custom:DataGridTemplateColumn>
The usercontrol you try to find, is (I assume as it's not in the code snippet) in the logical tree.
The binding is in the template which means that it's part of the visual tree. As they don't have a connection you cannot find it.

WPF Binding: Expression evaluation

I have a listbox in markup and a detail control. The listbox template defines a details button for each element. If this button is pressed a dependency property in the element's datasource is set to Visiblility == Visible. As long as I do have a selected item everything is OK. But if there is no selected item, the detail control is displayed always. Markup:
<Listbox x:Name="myListbox" />
<local:detailcontrol Visibility="{Binding ElementName=myListbox, Path=SelectedItem.DetailVisibility}" />
What I want is something like this:
<Listbox x:Name="myListbox" />
<local:detailcontrol Visibility="myListbox.SelectedItem != null ? {Binding ElementName=myListbox, Path=SelectedItem.DetailVisibility} : Visiblity.Hidden" />
Snippets both do not compile, but are provided to make my point clear.
Starting using the article at http://www.11011.net/wpf-binding-expressions I implemented something similar which solved my problem

Resources