I am new at WPF and of course I faced some issues with Bindings.
I have initialized RadCartesianChart and I want display data from different type of category lists. For each of those lists I want different color, but I fail to Bind Fill property to my Color property in code behind.
This is how my XAML looks like:
<telerik:RadCartesianChart Name="RevChart">
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid MajorYLineDashArray="5, 5" MajorLinesVisibility="Y">
<telerik:CartesianChartGrid.MajorYLineStyle>
<Style TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="Gray"/>
</Style>
</telerik:CartesianChartGrid.MajorYLineStyle>
</telerik:CartesianChartGrid>
</telerik:RadCartesianChart.Grid>
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:CategoricalAxis />
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis/>
</telerik:RadCartesianChart.VerticalAxis>
<telerik:AreaSeries CategoryBinding="Date" ValueBinding="Rev" Fill="{Binding Color}">
</telerik:AreaSeries>
</telerik:RadCartesianChart>
This is my C# code:
public class Revenue
{
public double Rev { get; set; }
public DateTime Date { get; set; }
public Color Color { get; set; }
}
List<Revenue> list = new List<Revenue>();
...
...
this.RevChart.Series[0].ItemsSource = list;
As a results I am getting correct picture, but color is default. So my binding of Color doesn't work. Is it problem in this line Fill={Binding Color} ? Why?
Its because Fill is a Brush and you are trying to assign a Color, this wont work.
You will have to assign your Color to the Color property of a SolidColorBrush in the Fill property.
Example
<telerik:AreaSeries CategoryBinding="Date" ValueBinding="Rev">
<telerik:AreaSeries.Fill>
<SolidColorBrush Color="{Binding Color}" />
</telerik:AreaSeries.Fill>
</telerik:AreaSeries>
Related
Good evening. A WFP binding question please.
Let's say that I have the following three classes:
public class Field
{
public string Data {get; set; }
public string TooltipText {get; set; }
public Field(string data, string tttext)
{
Data = data;
TooltipText = tttext;
}
}
public class FName : Field
{
public FName()
: base("","Enter first name")
{
}
}
public class Person
{
public FName FirstName {get; set; }
}
In XAML, assuming I have set the data context to Person in code, I can bind a TextBox's text and tooltip by
<TextBox Text="{Binding FirstName.Data, Mode=TwoWay}" Tooltip={Binding FirstName.TooltipText}" />
Is there a way to do this generically (if that's the first word) by referencing the base class' properties in a style so that I do not need to declare it for every TextBox? For instance, as a mockup:
<TextBox Binding="FirstName" Style="{StaticResource TextBoxStyle}">
and the style is something like
<Style x:Key="TextBoxStyle" TargetStyle="TextBox">
<Setter Property="Text" Value="{Binding Field.Data, Mode=TwoWay}" />
<Setter Property="Tooltip" Value="{Binding Field.TooltipText}" />
</Style>
All of my input fields are derived from a base class and it would be nice for the binding of data and tooltips to occur automatically from the Style.
Thank you in advance for any knowledge and/or help along these lines.
What you've posted will work fine, just bind directly to Data and TooltipText instead of Field.Data and Field.TooltipText.
I found the answer, which is exactly what you replied! I just need to set the DataContext to FieldName and now it all works perfectly.
<TextBox Style="{StaticResource TextBoxStyle}" DataContext={Binding FirstName}">
This data-binding stuff is so cool.
Thanks again for the help!
This is my ViewModel:
public ObservableCollection<Person> Persons;
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
And i want to create menu with all this Persons object from my List.
So in XAML i just create this:
<Menu Name="menuPersons" DockPanel.Dock="Top" SnapsToDevicePixels="True">
</Menu>
Code behind
MenuItem fileMenuItem = new MenuItem();
fileMenuItem.Header = "Persons";
menuPersons.Items.Add(fileMenuItem);
foreach (Person item in Persons)
{
fileMenuItem.Items.Add(new MenuItem
{
Header = item.FirstName,
});
}
But as you can see this looks ugly so my question is is pure XAML way to do that and bind all my object with all its properties ?
Update
So the solution works fine for me but i only have one issue:
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}"/>
</Style>
</Menu.ItemContainerStyle>
I have Style that i am using but so i cannot use this Menu.ItemContainerStyle
How can i solve this ? (note that i have another several different Menus that i using with this Style but i only need this Command for this Menu)
I am trying to "throw" several objects on a canvas.
I have 5 types of objects with several properties (like text, position, bitmap, and more)
Each type should be rendered differently (one type will be rendered as textblock, one as bitmapImage, ect.)
I have 5 observableCollections that holds all the objects of same type.
I can bind one of them (the one that represents text for example) to the canvas and using a data template with a textblock to bind each property to the right parameter (like visibility and localtion).
now my 2nd type should be bind to a bitmap.
How can I do that ? How can I bind 5 different types to the canvas and have each type converted to the right element ?
One possible way is to aggregate all collections to a single one... but then it tries to convert everything to the first type...
There`s a great answer to somehow related question that we can extend to make it work with your problem.
Say we have two types that can be dropped to Canvas:
public class TextClass
{
public string Text { get; set; }
}
public class RectangleClass
{
public Brush FillBrush { get; set; }
}
To facilitate the use of collection to bind to we can use the code from answer I mentioned but change ItemTemplate for our custom DataTemplateSelector:
<ItemsControl Name="icMain">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Left}" />
<Setter Property="Canvas.Top" Value="{Binding Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplateSelector>
<TestWPF:CustomTemplateSelector>
<TestWPF:CustomTemplateSelector.TextTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</TestWPF:CustomTemplateSelector.TextTemplate>
<TestWPF:CustomTemplateSelector.RectangleTemplate>
<DataTemplate>
<Rectangle Height="25" Width="25" Fill="{Binding FillBrush}" />
</DataTemplate>
</TestWPF:CustomTemplateSelector.RectangleTemplate>
</TestWPF:CustomTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
And that`s the template selector I used:
public class CustomTemplateSelector: DataTemplateSelector
{
public DataTemplate TextTemplate { get; set; }
public DataTemplate RectangleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is TextClass)
return TextTemplate;
else if (item is RectangleClass)
return RectangleTemplate;
else return base.SelectTemplate(item, container);
}
}
Well, all that`s left is to bind our collection. I used simple List in code behind just for test:
List<object> aggregation = new List<object>()
{
new TextClass() { Text = "Some test text" },
new RectangleClass() { FillBrush = new SolidColorBrush(Colors.Tomato)}
};
icMain.ItemsSource = aggregation;
This code shows some test text and yummy tomato rectangle. These sample objects do not have any positioning logic, but I figured you have that already.
I am new to WPF and am trying to bind a context menu to an ObservableCollection of models. I am able to get the context menu to display but I can't get the commands to fire. Here is my code
<ContextMenu ItemsSource="{Binding ContextMenuList}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="MenuItem.Header" Value="{Binding Name}" />
<Setter Property="MenuItem.ItemsSource" Value ="{Binding Children}" />
<Setter Property="Command" Value="{Binding MenuCommand}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
In the View Model I have
public class MenuItemViewModel
{
public string Name { get; set; }
public ObservableCollection Children { get; set; }
public ICommand MenuCommand;
public MenuItemViewModel(string name, ObservableCollection pChildren, ICommand pCommand)
{
this.Name = name;
this.Children = pChildren;
this.MenuCommand = pCommand;
}
}
and I populate the collection
public void AddContextMenuItems()
{
this.ContextMenuList = new ObservableCollection<MenuItemViewModel>();
ICommand pCommand = new ActionCommand(() => this.ChangeChartType());
MenuItemViewModel ohlc = new MenuItemViewModel("OHLC",null,pCommand);
MenuItemViewModel candlestick = new MenuItemViewModel("CandleStick");
ObservableCollection<MenuItemViewModel> chartTypeColl = new ObservableCollection<MenuItemViewModel>();
chartTypeColl.Add(ohlc);
chartTypeColl.Add(candlestick);
this.ContextMenuList.Add(new MenuItemViewModel("ChartType",chartTypeColl));
}
I don't see the ChangeChartType method ever get triggered, what I am I doing wrong here ?
Try to change MenuCommand field to property
public ICommand MenuCommand { get; set; }
Hope this work for you. I haven't tried this though.
Given the following XAML snippet:
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="ContextMenuItemStyle">
<Setter Property="MenuItem.Header" Value="{Binding Text}"/>
<Setter Property="MenuItem.ItemsSource" Value="{Binding Children}"/>
<Setter Property="MenuItem.Command" Value="{Binding Command}" />
</Style>
<ContextMenu x:Key="contextMenu" ItemsSource="{Binding MenuOptions}" ItemContainerStyle="{StaticResource ContextMenuItemStyle}" />
</ResourceDictionary>
</UserControl.Resources>
<DockPanel>
<TextBox Height="30" DockPanel.Dock="Top" ContextMenu="{StaticResource contextMenu}" />
<Button Content="Add Menu Item" DockPanel.Dock="Top" Command="{Binding AddMenuItem}" />
</DockPanel>
And View Model:
public class MyViewModel {
public ObservableCollection<MenuItem> DocumentExplorerMenuOptions { get; set; }
MenuItem firstMenuItem;
MenuItem secondMenuItem;
public MyViewModel() {
firstMenuItem = new MenuItem("First") { Command = new DelegatingCommand(x => MessageBox.Show("First Selected") };
secondMenuItem = new MenuItem("Second") { Command = new DelegatingCommand(x => MessageBox.Show("Second Selected") };
MenuOptions = new ObservableCollection<MenuItem> { firstMenuItem, secondMenuItem };
AddMenuItem = new DelegateCommand<object>(x => firstMenuItem.Children.Add(
new MenuItem("Child of First")));
}
public DelegateCommand<object> AddMenuItem { get; set; }
}
And class:
public class MenuItem {
public MenuItem(string text) {
Text = text;
Children = new List<MenuItem>();
}
public string Text { get; set; }
public List<MenuItem> Children { get; private set; }
public ICommand Command { get; set; }
}
Clicking the button does add the child to firstMenuItem but it does not appear in the context menu of the TextBox.
I can't figure out how to make the context menu show the dynamic content of the context menu. Any thoughts?
I would not bind to a collection of MenuItems but rather to a more data-driven collection which may contain the MenuItem header, a command which is executed upon click and another collection of such items for the sub-items. Then you could use a (Hierarchical)DataTemplate to generate the menu on the fly. Doing so would probably take care of update issues if your datatype implements the necessary interfaces.
Edit: You seem to have such a datatype already, could you post its code?
Edit2: I think the problem is that you use a style that explicitly needs to be applied (it is probably only being applied to the main context menu, not the sub-items), as noted before i'd suggest a HierarchicalDataTemplate.
Edit3: lol...
public List<MenuItem> Children { get; private set; }
Of course it's not going to update if it's a List and not an ObservableCollection.
(The class is quite badly designed overall by the way, Lists should normally not even have a private setter, they should be properties with just a getter to a readonly field)