I am learning WPF and have spent waaaay too much time trying to solve this simple task.
My goal is to add two RibbonComboBoxes to a ribbon control. One for Categories, and another for Subcategories. Whenever the user changes the Category, I would like to have the Subcategories combo box update to show the subcategories for the current category.
XAML:
<RibbonTab Header="Home">
<RibbonGroup Header="Category">
<RibbonComboBox Label="Category:" HorizontalContentAlignment="Left" SelectionBoxWidth="250" Focusable="False">
<RibbonGallery Name="galCategory" DisplayMemberPath="Text" SelectedValuePath="Value">
</RibbonGallery>
</RibbonComboBox>
<RibbonComboBox Label="Subcategory:" HorizontalContentAlignment="Left" SelectionBoxWidth="250">
<RibbonGallery Name="galSubcategory" DisplayMemberPath="Text" SelectedValuePath="Value">
</RibbonGallery>
</RibbonComboBox>
</RibbonGroup>
</RibbonTab>
I found that only by adding the RibbonGallery element, I can access methods that allow me to populate the combo box. However, while my data shows in the list, the items cannot be selected by the user. (Clicking items in the list has no effect whatsoever.)
Can anyone tell me how to populate these controls?
Note: Bonus points to anyone who can tell me how to make the two combo boxes align up to each other regardless of the length of text in the label!
Add a RibbonGalleryCategory control inside RibbonGallery and then populate it. Add a selection change event listener to RibbonGallery:
XAML:
<RibbonComboBox Label="Category:" Name="rcmbCategory" SelectionBoxWidth="100" Height="20" HorizontalContentAlignment="Center">
<RibbonGallery Name="galCategory" DisplayMemberPath="Text" SelectedValuePath="Value" SelectionChanged="RibbonGallery_SelectionChanged">
<RibbonGalleryCategory Name="rgcCategory"/>
</RibbonGallery>
</RibbonComboBox>
.CS:
public MainWindow()
{
InitializeComponent();
for(int i=0;i<=10;i++)
rgcCategory.Items.Add(i);
}
private void RibbonGallery_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
MessageBox.Show(rcmbCategory.SelectionBoxItem.ToString());
}
Refer to CodeProject: RibbonComboBox for more information.
Related
I'm currently making a transferring data from one listbox to another.
With WPF I have:
<Grid>
<ListBox Margin="10,29,194,301" Name="LeftListBox"/>
<ListBox Margin="0,29,16,301" Name="RightListBox" HorizontalAlignment="Right" Width="173" />
<Button Name="AddButton" Height="23" Margin="34,135,227,0" VerticalAlignment="Top"
Click="AddButton_Click">Add >></Button>
<Button Name="RemoveButton" Margin="227,135,34,264"
Click="RemoveButton_Click"><< Remove</Button>
</Grid>
For my C# code, I created two methods that loads the left box's elements by using an array of Strings and the right one's.
Now My issue is that I want an element of the left box to be placed into the right box after the last element of the right box's list. So when I click on add, it should execute this method:
private void AddButton_Click(object sender, RoutedEventArgs e)
{
// Find the right item and it's value and index
currentItemText = LeftListBox.SelectedValue.ToString();
currentItemIndex = LeftListBox.SelectedIndex;
ObservableCollection<string> oList;
oList = new System.Collections.ObjectModel.ObservableCollection<string>(toRemoveList);
RightListBox.DataContext = oList;
Binding binding = new Binding();
RightListBox.SetBinding(ListBox.ItemsSourceProperty, binding);
(RightListBox.ItemsSource as ObservableCollection<string>).Add(currentItemText);
if (toAddList != null)
{
toAddList.RemoveAt(currentItemIndex);
}
// Refresh data binding
ApplyDataBinding();
}
But the problem is that when I select an item from the left box, then click on add, it adds the new item into the right box but when I add a second item, it replaces the last one item that I added at the first step.
After that, the second problem is, how would be implemented the RemoveButton_Click ? Is it the same way as the previous method ?
You need not to do this much of code for this. Follow below given steps for more robust and maintainable approach.
Create two Observablecollection corresponding to left and right ListBox
Bind Observablecollection to ListBox
On Add button click, remove the item from observable collection assigned to left listbox and add to the oberservable collection binded to right grid.
You need not to update the bindings explicitly. Observable collection notify the collection changes automatically.
In code -
public ObservableCollection<ApplicationFormats> Formats { get; set; }
Xaml -
<ListBox Name="LeftListBox" ItemsSource="{Binding Formats}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have 4 radio buttons that every one of them shows a different list in a combobox that attached to them. The radio button should be available only after pressing a some button. I want one of the radio button to be chosen and than the last row on the combo list to be chosen automatically.
MAINWINDOWS.XAML
<!--RadioButtons-->
<RadioButton x:Name="RadioButtonA" GroupName="Button" Content="A" Margin="0,5,0,0" Grid.Column="0" Click="RadioButtonA_Click" />
<RadioButton x:Name="RadioButtonB" GroupName="Button" Content="B" Margin="0,20,0,0" Grid.Column="0" Click="RadioButtonB_Click"/>
<RadioButton x:Name="RadioButtonC" GroupName="Button" Content="C" Margin="0,35,0,0" Grid.Column="0" Click="RadioButtonC_Click"/>
<RadioButton x:Name="RadioButtonD" GroupName="Button" Content="D" Margin="0,50,0,0" Grid.Column="0" Click="RadioButtonD_Click"/>
<!--ComboBox-->
<ComboBox
x:Name="ComboBox"
IsEnabled="false"
Grid.Column="1"
Width="240"
Height="30"
VerticalAlignment="Top" Margin="0,8,0,0"
SelectionChanged="ComboBoxSelectionChanged" >
</ComboBox>
ViewModel: Example for one of the radiobuttons
private void RadioButtonA_Click(object sender, RoutedEventArgs e)
{
IdComboBox.SelectedValue = string.Empty;
IdComboBox.IsEnabled= true;
IdComboBox.Items = AList;
currentIdentifier = Identifier.A;
}
You mentioned "ViewModel", but you actually don't use MVVM.
Using event handlers to set state of many related controls is a doomed way - because complexity increases in proportion to the square of the amount of controls. You have to use MVVM, the approach when properties of controls are projected to a property of a model. Then you can use triggers to set controls state depending on the model property values. Or, if you consider triggers too verbose, you can use QuickConverter, this library helps to simplify code.
Even if you don't like/cannot use any of them, please, use triggers to set state of comboboxes.
I have a combobox that pulls a set of options from CRM. The combobox was created in .xaml using the code:
<ComboBox x:Name="cmbTransfer" Width="200" Height="40" BorderBrush="Transparent" BorderThickness="0"
Margin="0,0,20,0" AutomationProperties.Name="Transfer State" IsTextSearchEnabled="true" FontSize="20" SelectionChanged="Transfer_Click" IsEnabled="False"/>
In C#, I set the comboboxItem.Content to "Transfer". Then I fill the comboBoxItem.Content with languages to transfer to that are pulled from CRM.
Right now, when I click the transfer dropdown, I get the following:
Transfer Dropdown UI
I want the "transfer" in the dropdown menu to not appear. Do you guys have any ideas?
#Sajeetharan: The combobox is populated using the line:
comboBoxItem.Content = (object)current.Attributes["uscb_language"].ToString();
The entity uscb_language is a list of languages from CRM
The action is fired to populate this field with the following method:
private void Transfer_Click(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (cmbTransfer.SelectedIndex != 0)
{
//UpdatePhoneCallActityWithTransferInfo("1233");
this.FireRequestAction(new RequestActionEventArgs("CTIControl", "FireEvent", "HandleTransfer"));
//await Task.Delay(20000);
}
}
I am trying to make a form of sorts where the user will have the option to press a button to dynamically add more text boxes, with each text box to contain the path of a directory to exclude from a search. This is relatively trivial using code-behind, but my problem is doing it in proper MVVM.
The general markup for the structure is:
<ScrollViewer >
<StackPanel>
<DockPanel LastChildFill="False">
<TextBox DockPanel.Dock="Left"/>
<Button DockPanel.Dock="Right"
Content="+"/>
</DockPanel>
</StackPanel>
</ScrollViewer>
Clicking the button will add a new DockPanel with a TextBox and Button to the StackPanel. All buttons but the bottom-most will change to a minus sign. How can I somehow bind to the text of all the text boxes?
As an aside, once/if I get this working, would it be better to make it into its own component?
Quick pseudo-code to get you started:
cs (view model):
// INotifyPropertyChanged if you need, as well as full-properties with notification
public class Item
{
public string Text {get; set;}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
void OnCommandAdd() => Items.Add(new Item());
xaml (view):
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The idea is to use control able to display list (e.g. ItemsControl) and collection of items in view model. Adding new element to view is done by adding item to that collection.
All TextBoxes will have Text bound to corresponding property of item.
My name is Andrea this is my first post ever.
Frequently you have helped me as a simple reader, now I'm writing because I wanted to direct support.
I have to create and a tab control and with a button "Add Tab" I have to add a new tab with the same content.
Up to this everything is fine.
Within Tab I have a textedit and a combobox.
My problems are two:
1 How do I load the contents of the combobox for each tab I add?
2 Every time I write the text of and a edit tab override also edit the text of the other tab.
Here the code:
Data Template in Xaml:
<DataTemplate x:Key="tabItemContent">
<dxlc:LayoutGroup Orientation="Vertical" Header="Target Description" IsCollapsible="True">
<!--Name-->
<dxlc:LayoutItem>
<dxlc:LayoutGroup Orientation="Horizontal" ItemSpace="4" >
<dxlc:LayoutItem Label="Name" Margin="10">
<dxe:TextEdit x:Name="TextEdit_NameTarget"/>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
</dxlc:LayoutItem>
<!--Nation e Label-->
<dxlc:LayoutItem>
<dxlc:LayoutGroup Orientation="Horizontal" ItemSpace="12" >
<dxlc:LayoutItem Label="Nation" Margin="10">
<ComboBox x:Name="ComboBox_TargetNazione" />
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
</DataTemplate>
C#:
private void Button_Click_Add(object sender, RoutedEventArgs e)
{
DataTemplate tabItemDataTemplate = this.TryFindResource("tabItemContent") as DataTemplate;
DXTabItem tabItem = new DXTabItem();
tabItem.Header = "New Tab";
tabItem.ContentTemplate = tabItemDataTemplate;
tabControl_Targets.Items.Add(tabItem);
}
Here's where to load the list into the combobox:
private void LoadComboBoxNation()
{
ComboBox_TargetNazione.ItemsSource =
ManagementTriple.Istance().get_Nation_byTipologyAndContext(ComboBox_TypologyScenario.SelectedItem.ToString(),
ComboBox_ContextScenario.SelectedItem.ToString());
controlloselecteditem(ComboBox_SourceNazione.SelectedItem.ToString());
controlloselecteditem(ComboBox_TargetNazione.SelectedItem.ToString());
}
Thank you all for the help that you can give me.
DataTemplates require a simple but fundamental requirement to work properly: you should use the ViewModel-First approach.
Ideally, your tab control should have a Binding to some ViewModel. Then, if you want another tab to appear, you should use your button click to call a Command in your ViewModel, then the ViewModel would add another item to your TabControl ItemsSource property (which would be some collection), and the new item would be displayed "automagically" with its respective DataTemplate.
The idea of WPF is to replace all this imperative code in the View (like the one you posted) with a more indirect one, where your only worry is to manipulate things in the ViewModel, and the "Dumb View" just follows.
Hope this helps, but don't hesitate to ask for additional details in the comments.