I tried to show the RSS text in one line but it doesn't work.
Any "title" from the RSS gets a new line.
there is any way to solve it?
<UserControl x:Class="Example.UserControls.Footer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:EcoBuy.UserControls"
mc:Ignorable="d"
d:DesignHeight="54" d:DesignWidth="1920">
<UserControl.Resources>
<XmlDataProvider x:Key="DataRss"
XPath="//item"
Source="https://rss.walla.co.il/feed/127"></XmlDataProvider>
</UserControl.Resources>
<Grid FlowDirection="RightToLeft">
<ListBox ItemsSource="{Binding Source={StaticResource DataRss}}"
Margin="0,0,0,-110">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock x:Name="rssText" Text="{Binding XPath=title}" TextWrapping="NoWrap">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
You can try to use MaxLines="1"
Maybe try to use an IValueConverter to remove possible newlines in your feed?
Something like this:
public class RemoveNewlinesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string text)
{
return text.Replace("\n", "").Replace("\r", "");
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have an issue with setting the visibility of a control when specifying the context using ElementName.
For some reason wpf seems to behave differently when using ElementName, versus using the context that is set from the code-behind.
The following code works fine. The collection contains two elements, and the button is set to visible.
MainWindow.xaml
<Window x:Class="WpfObservableCollectionVisibility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfObservableCollectionVisibility"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" x:Name="MyWindow">
<Window.Resources>
<ResourceDictionary>
<local:EmptyListVisibilityConverter x:Key="EmptyListVisibilityConverter"></local:EmptyListVisibilityConverter>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Height="50" Width="100" Content="Button" VerticalAlignment="top" Visibility="{Binding MenuItems, Converter={StaticResource EmptyListVisibilityConverter}}"></Button>
<Grid Width="200" Height="200">
<ItemsControl ItemsSource="{Binding MenuItems}" Focusable="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static readonly DependencyProperty MenuItemsProperty =
DependencyProperty.Register(
"MenuItems", typeof(ObservableCollection<MyItem>),
typeof(MainWindow),
new FrameworkPropertyMetadata(default (ObservableCollection<MyItem>),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);
public MainWindow()
{
InitializeComponent();
MenuItems = new ObservableCollection<MyItem>();
MenuItems.Add(new MyItem("Entry 1"));
MenuItems.Add(new MyItem("Entry 2"));
DataContext = this;
}
public ObservableCollection<MyItem> MenuItems
{
get => (ObservableCollection<MyItem>) GetValue(MenuItemsProperty);
set => SetValue(MenuItemsProperty, value);
}
}
public class MyItem
{
public MyItem(string name)
{
this.Name = name;
}
public string Name { get; set; }
}
public class EmptyListVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Trace.WriteLine($"Do conversion");
if (value == null)
{
Trace.WriteLine($"Conversion value was null");
return Visibility.Collapsed;
}
else
{
ICollection list = value as ICollection;
if (list != null)
{
if (list.Count == 0)
{
Trace.WriteLine($"Count is zero");
return Visibility.Hidden;
}
else
{
Trace.WriteLine($"Count is greater than zero");
return Visibility.Visible;
}
}
else
{
Trace.WriteLine($"Was not a collection");
return Visibility.Visible;
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
However, when I set the ElementName context for the ItemsControl and Button, the ItemsControl still displays fine, but the Button is not shown, because the converter for some reason receives an empty collection.
<Button Height="50" Width="100" Content="Button" VerticalAlignment="top" Visibility="{Binding MenuItems, ElementName=MyWindow, Converter={StaticResource EmptyListVisibilityConverter}}"></Button>
...
<ItemsControl ItemsSource="{Binding MenuItems, ElementName=MyWindow}" Focusable="False">
I tried debugging it, but I don't understand what is wrong. I don't know where this empty collection comes from. I also don't understand why the ItemsControl works fine. I feel like either both should work, or neither.
I have a WPF window that uses multiple viewmodel objects as its DataContext. The window has a control that binds to a property that exists only in some of the viewmodel objects. How can I bind to the property if it exists (and only if it exists).
I am aware of the following question/answer: MVVM - hiding a control when bound property is not present. This works, but gives me a warning. Can it be done without the warning?
Thanks!
Some example code:
Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="1" Name="ListView" Margin="25,0,25,0" ItemsSource="{Binding Path=Lst}"
HorizontalContentAlignment="Center" SelectionChanged="Lst_SelectionChanged">
</ListBox>
<local:SubControl Grid.Row="3" x:Name="subControl" DataContext="{Binding Path=SelectedVM}"/>
</Grid>
SubControl Xaml:
<UserControl x:Class="WpfApplication1.SubControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffAlways}"/>
<CheckBox IsChecked="{Binding Path=Always}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Row="3" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffSometimes}"/>
<CheckBox IsChecked="{Binding Path=Sometimes}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
</Grid>
MainWindow Code Behind:
public partial class MainWindow : Window
{
ViewModel1 vm1;
ViewModel2 vm2;
MainViewModel mvm;
public MainWindow()
{
InitializeComponent();
vm1 = new ViewModel1();
vm2 = new ViewModel2();
mvm = new MainViewModel();
mvm.SelectedVM = vm1;
DataContext = mvm;
}
private void Lst_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lstBx = sender as ListBox;
if (lstBx != null)
{
if (lstBx.SelectedItem.Equals("VM 1"))
mvm.SelectedVM = vm1;
else if (lstBx.SelectedItem.Equals("VM 2"))
mvm.SelectedVM = vm2;
}
}
}
MainViewModel (DataContext of MainWindow):
public class MainViewModel : INotifyPropertyChanged
{
ObservableCollection<string> lst;
ViewModelBase selectedVM;
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel()
{
Lst = new ObservableCollection<string>();
Lst.Add("VM 1");
Lst.Add("VM 2");
}
public ObservableCollection<string> Lst
{
get { return lst; }
set
{
lst = value;
OnPropertyChanged("Lst");
}
}
public ViewModelBase SelectedVM
{
get { return selectedVM; }
set
{
if (selectedVM != value)
{
selectedVM = value;
OnPropertyChanged("SelectedVM");
}
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
ViewModel1 (with sometimes property):
public class ViewModel1 : ViewModelBase, INotifyPropertyChanged
{
private bool _always;
private string _onOffAlways;
private bool _sometimes;
private string _onOffSometimes;
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel1()
{
_always = false;
_onOffAlways = "Always Off";
_sometimes = false;
_onOffSometimes = "Sometimes Off";
}
public bool Always
{
get { return _always; }
set
{
_always = value;
if (_always)
OnOffAlways = "Always On";
else
OnOffAlways = "Always Off";
OnPropertyChanged("Always");
}
}
public string OnOffAlways
{
get { return _onOffAlways; }
set
{
_onOffAlways = value;
OnPropertyChanged("OnOffAlways");
}
}
public bool Sometimes
{
get { return _sometimes; }
set
{
_sometimes = value;
if (_sometimes)
OnOffSometimes = "Sometimes On";
else
OnOffSometimes = "Sometimes Off";
OnPropertyChanged("Sometimes");
}
}
public string OnOffSometimes
{
get { return _onOffSometimes; }
set
{
_onOffSometimes = value;
OnPropertyChanged("OnOffSometimes");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
ViewModel2 (without Sometimes property):
public class ViewModel2 : ViewModelBase, INotifyPropertyChanged
{
private bool _always;
private string _onOffAlways;
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel2()
{
_always = false;
_onOffAlways = "Always Off";
}
public bool Always
{
get { return _always; }
set
{
_always = value;
if (_always)
OnOffAlways = "Always On";
else
OnOffAlways = "Always Off";
OnPropertyChanged("Always");
}
}
public string OnOffAlways
{
get { return _onOffAlways; }
set
{
_onOffAlways = value;
OnPropertyChanged("OnOffAlways");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class AlwaysVisibleConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value,
Type targetType, object parameter, CultureInfo culture)
{
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
There are many different ways one could approach your scenario. For what it's worth, the solution you already have seems reasonable to me. The warning you get (I presume you are talking about the error message output to the debug console) is reasonably harmless. It does imply a potential performance issue, as it indicates WPF is recovering from an unexpected condition. But I would expect the cost to be incurred only when the view model changes, which should not be frequent enough to matter.
Another option, which is IMHO the preferred one, is to just use the usual WPF data templating features. That is, define a different template for each view model you expect, and then let WPF pick the right one according to the current view model. That would look something like this:
<UserControl x:Class="TestSO46736914MissingProperty.UserControl1"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:l="clr-namespace:TestSO46736914MissingProperty"
mc:Ignorable="d"
Content="{Binding}"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<DataTemplate DataType="{x:Type l:ViewModel1}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffAlways}"/>
<CheckBox IsChecked="{Binding Path=Always}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Row="3" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffSometimes}"/>
<CheckBox IsChecked="{Binding Path=Sometimes}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type l:ViewModel2}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffAlways}"/>
<CheckBox IsChecked="{Binding Path=Always}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
</Grid>
</DataTemplate>
</UserControl.Resources>
</UserControl>
I.e. just set the Content of your UserControl object to the view model object itself, so that the appropriate template is used to display the data in the control. The template for the view model object that doesn't have the property, doesn't reference that property and so no warning is generated.
Yet another option, which like the above also addresses your concern about the displayed warning, is to create a "shim" (a.k.a. "adapter") object that mediates between the unknown view model type and a consistent one the UserControl can use. For example:
class ViewModelWrapper : NotifyPropertyChangedBase
{
private readonly dynamic _viewModel;
public ViewModelWrapper(object viewModel)
{
_viewModel = viewModel;
HasSometimes = viewModel.GetType().GetProperty("Sometimes") != null;
_viewModel.PropertyChanged += (PropertyChangedEventHandler)_OnPropertyChanged;
}
private void _OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
_RaisePropertyChanged(e.PropertyName);
}
public bool Always
{
get { return _viewModel.Always; }
set { _viewModel.Always = value; }
}
public string OnOffAlways
{
get { return _viewModel.OnOffAlways; }
set { _viewModel.OnOffAlways = value; }
}
public bool Sometimes
{
get { return HasSometimes ? _viewModel.Sometimes : false; }
set { if (HasSometimes) _viewModel.Sometimes = value; }
}
public string OnOffSometimes
{
get { return HasSometimes ? _viewModel.OnOffSometimes : null; }
set { if (HasSometimes) _viewModel.OnOffSometimes = value; }
}
private bool _hasSometimes;
public bool HasSometimes
{
get { return _hasSometimes; }
private set { _UpdateField(ref _hasSometimes, value); }
}
}
This object uses the dynamic feature in C# to access the known property values, and uses reflection on construction to determine whether or not it should try to access the Sometimes (and related OnOffSometimes) property (accessing the property via the dynamic-typed variable when it doesn't exist would throw an exception).
It also implements the HasSometimes property so that the view can dynamically adjust itself accordingly. Finally, it also proxies the underlying PropertyChanged event, to go along with the delegated properties themselves.
To use this, a little bit of code-behind for the UserControl is needed:
partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public ViewModelWrapper ViewModelWrapper { get; private set; }
public UserControl1()
{
DataContextChanged += _OnDataContextChanged;
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
private void _OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ViewModelWrapper = new ViewModelWrapper(DataContext);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViewModelWrapper)));
}
}
With this, the XAML is mostly like what you originally had, but with a style applied to the optional StackPanel element that has a trigger to show or hide the element according to whether the property is present or not:
<UserControl x:Class="TestSO46736914MissingProperty.UserControl1"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:l="clr-namespace:TestSO46736914MissingProperty"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid DataContext="{Binding ViewModelWrapper, RelativeSource={RelativeSource AncestorType=UserControl}}">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffAlways}"/>
<CheckBox IsChecked="{Binding Path=Always}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Row="3" Orientation ="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,5,0,5">
<StackPanel.Style>
<p:Style TargetType="StackPanel">
<p:Style.Triggers>
<DataTrigger Binding="{Binding HasSometimes}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</p:Style.Triggers>
</p:Style>
</StackPanel.Style>
<TextBlock Margin="5,0,5,0" Text="{Binding Path=OnOffSometimes}"/>
<CheckBox IsChecked="{Binding Path=Sometimes}">
<TextBlock Text="On/Off"/>
</CheckBox>
</StackPanel>
</Grid>
</UserControl>
Note that the top-level Grid element's DataContext is set to the UserControl's ViewModelWrapper property, so that the contained elements use that object instead of the view model assigned by the parent code.
(You can ignore the p: XML namespace…that's there only because Stack Overflow's XAML formatting gets confused by <Style/> elements that use the default XML namespace.)
While I in general would prefer the template-based approach, as the idiomatic and inherently simpler one, this wrapper-based approach does have some advantages:
It can be used in situations where the UserControl object is declared in an assembly different from the one where the view model types are declared, and where the latter assembly cannot be referenced by the former.
It removes the redundancy that is required by the template-based approach. I.e. rather than having to copy/paste the shared elements of the templates, this approach uses a single XAML structure for the entire view, and shows or hides elements of that view as appropriate.
For completeness, here is the NotifyPropertyChangedBase class used by the ViewModelWrapper class above:
class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
_RaisePropertyChanged(propertyName);
}
protected void _RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
For what it's worth, I prefer this approach to re-implementing the INotifyPropertyChanged interface in each model object. The code is a lot simpler and easier to write, simpler to read, and less prone to errors.
Here's a fairly simple solution using DataTriggers and a custom converter:
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={HasPropertyConverter PropertyName=Sometimes}}" Value="True">
<Setter Property="IsChecked" Value="{Binding Sometimes}" />
</DataTrigger>
</Style.Triggers>
</Style>
The converter:
public class HasPropertyConverter : IValueConverter
{
public string PropertyName { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (string.IsNullOrWhiteSpace(PropertyName))
return DependencyProperty.UnsetValue;
return value?.GetType().GetProperty(PropertyName) != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
public class HasPropertyConverterExtension : MarkupExtension
{
public string PropertyName { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
=> new HasPropertyConverter { PropertyName = PropertyName };
}
I have created bar chart control in wpf using system.windows.controls.datavisualization.toolkit dll. I want to specify the minimum and maximum for the Y axis.
Here the Bar-chart
`
<Grid >
<barChartToolkit:Chart Height="280" HorizontalAlignment="Stretch" Title="Resource Availability" Name="columnChart" Background="White" VerticalAlignment="Stretch" Width="360">
<barChartToolkit:ColumnSeries DependentValuePath="Value" IndependentValuePath="Name" ItemsSource="{Binding}" Title="Resources" />
</barChartToolkit:Chart>
</Grid>
`
Now I'm created the list and binded DataContext of the chart
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
showColumnChart();
}
private void showColumnChart()
{
List<BarCHartData> valueList = new List<BarCHartData>();
valueList.Add(new BarCHartData() { Name = "Developer", Value = 10 });
valueList.Add(new BarCHartData() { Name = "Tester", Value = 20 });
valueList.Add(new BarCHartData() { Name = "QA", Value = 30 });
columnChart.DataContext = valueList;
}
}
public class BarCHartData
{
public string Name { get; set; }
public int Value { get; set; }
}
here my bar chart plotting like below image
I have tried with below code
<Window x:Class="WpfToolkitChart.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:barChartToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit">
<Grid >
<barChartToolkit:Chart Height="280" HorizontalAlignment="Stretch" Title="Resource Availability" Name="columnChart" Background="White" VerticalAlignment="Stretch" Width="360">
<barChartToolkit:ColumnSeries DependentValuePath="Value" IndependentValuePath="Name" ItemsSource="{Binding}" Title="Resources" />
<barChartToolkit:Chart.Axes>
<barChartToolkit:LinearAxis Orientation="Y" Minimum="0" Maximum="100"/>
</barChartToolkit:Chart.Axes>
</barChartToolkit:Chart>
</Grid>
but this code removing the grid line of the graph like below image
how can i set the maximum and minimum value to the Y-Axis with the gridlines?
You just need to set ShowGridLines="True" in your LinearAxis:
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp55"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
x:Class="WpfApp55.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="array1" Type="{x:Type local:BarChartData}">
<local:BarChartData Name="Developer" Value="25" />
<local:BarChartData Name="Tester" Value="50" />
<local:BarChartData Name="QA" Value="75" />
</x:Array>
</Window.Resources>
<Grid>
<chartingToolkit:Chart Title="Sample Chart">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Minimum="0"
Maximum="100"
Orientation="Y"
ShowGridLines="True" />
</chartingToolkit:Chart.Axes>
<chartingToolkit:ColumnSeries DependentValuePath="Value"
IndependentValuePath="Name"
ItemsSource="{StaticResource array1}"/>
</chartingToolkit:Chart>
</Grid>
If you want to limit the values for display, you could use a converter and DependentValueBinding instead of DependentValuePath
public class RangeConverter : IValueConverter
{
public double Min { get; set; }
public double Max { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var d = System.Convert.ToDouble(value, culture);
return Math.Max(Min, Math.Min(Max, d));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Converter resource:
<local:RangeConverter x:Key="rangeConverter" Max="100" Min="0"/>
Usage
<DVC:ColumnSeries
DependentValueBinding="{Binding Value,Converter={StaticResource rangeConverter}}"
IndependentValuePath="Name"
ItemsSource="{Binding}"
Title="Resources"/>
I have xaml file where I put 2 TextBox where I can put login and password. After then Button "Login" should be visible. Here is my code:
TreeView.xaml file:
<UserControl x:Class="LayoutMVVM.Views.TreeView"
xmlns:local="clr-namespace:LayoutMVVM.Views"
xmlns:Treemodels="clr-namespace:LayoutMVVM.ViewModels" .../>
<UserControl.Resources>
<Treemodels:VBConverter x:Key="VBConverter" />
</UserControl.Resources>
<Grid>
....
<TextBox Grid.Row="2" Grid.Column="2" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<Button Grid.Row="3" Grid.Column="3" Visibility="{Binding IsVerifyTrue, Converter={StaticResource VBConverter}}" Content="Login" />
</Grid>
TreeView.xaml.cs
namespace LayoutMVVM.Views
{
public partial class TreeView : UserControl
{
public TreeView()
{
InitializeComponent();
}
public TreeView _isVerifyTrue;
public TreeView IsVerifyTrue
{
get { return this; }
set
{
_isVerifyTrue = value;
OnPropertyChanged(() => IsVerifyTrue);
}
}
private void OnPropertyChanged(Func<object> p)
{
throw new NotImplementedException();
}
private string _login;
public string Login
{
get { return _login; }
set
{
_login = value;
IsVerifyTrue = this;
OnPropertyChanged(() => Login);
}
}
private string _password;
public string Password
{
get { return _password; }
set
{
_password = value;
IsVerifyTrue = this;
OnPropertyChanged(() => Password);
}
}
}
and seperate class for VBConverter.cs:
namespace LayoutMVVM.ViewModels
{
public class VBConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is TreeView)
{
var tv = value as TreeView;
bool result = !string.IsNullOrEmpty(tv.Login)
&& !string.IsNullOrEmpty(tv.Password);
return result? Visibility.Visible : Visibility.Hidden;
}
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
When I start app button is always visible and I'm not know what is wrong.
You'll need a MultiValueConverter for this. See below example :
XAML :
<Window x:Class="SOSample1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SOSample1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<local:VisibilityConverter x:Key="VisibilityConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="100" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="user" Height="100" Width="200" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<TextBox Grid.Row="1" Name="password" Height="100" Width="200" Text="{Binding Login, UpdateSourceTrigger=PropertyChanged}" Background="AliceBlue" />
<Button Grid.Row="2" Content="Login" Height="100" Width="200" >
<Button.Visibility>
<MultiBinding Converter="{StaticResource VisibilityConverter}" >
<Binding ElementName="user" Path="Text" />
<Binding ElementName="password" Path="Text" />
</MultiBinding>
</Button.Visibility>
</Button>
</Grid>
Converter :
public class VisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool result = false;
if (values != null)
{
foreach (var item in values)
{
result = (item as string).Length > 0;
if (!result) break;
}
}
return (Visibility)new BooleanToVisibilityConverter().Convert(result, targetType, parameter, culture);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
OUTPUT