How to hide combobox toggle button if there is only one item? - wpf

I have a WPF application. In one window there is a combobox..and I want to hide the toggle button and disable the combo box if there is only one item.
How would I achieve this ?
I have tried the below code for hiding the toggle button. But of no luck
Any help would be appreciated. thanks
<ComboBox x:Name="CList" ItemsSource="{Binding Path=C}" >
<Style TargetType="{x:Type ToggleButton}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count, ElementName=CList}" Value="1">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox>

The better solution is to replace the template of combo box with a control template(which only contain textblock) when the item count is zero.
Here is the xaml for the same.
<ComboBox Name="CList" ItemsSource="{Binding Path=C}"
SelectedItem="{Binding Path=CC}" VerticalAlignment="Center" Margin="0,0,10,0" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count, ElementName=CList}" Value="1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="{Binding Items[0], ElementName=CList}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>

You would need to change the Template of the ComboBox and implement the trigger inside that. You have no access to the controls in the template from the outside.
(You could copy and modify the existing template, directly modifying a part of the template is practically impossible)

You can always use a Converter also:
(Sorry I didn't fully read your question)
Converters
using System;
using System.Windows;
using System.Windows.Data;
using System.Globalization;
namespace WPFSandbox
{
public class ComboBoxItemCountToEnabledConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.GetType() == typeof(Int32))
{
if ((int)value > 1)
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class ComboBoxItemCountToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.GetType() == typeof(Int32))
{
if ((int)value > 1)
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
XAML
<Window
...
...
xmlns:converters="clr-namespace:WPFSandbox">
<Window.Resources>
<converters:ComboBoxItemCountToVisibilityConverter x:Key="ComboBoxItemCountToVisibilityConverter"/>
<converters:ComboBoxItemCountToEnabledConverter x:Key="ComboBoxItemCountToEnabledConverter"/>
</Window.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding C}" IsEnabled="{Binding Path=C.Count, Converter={StaticResource ComboBoxItemCountToEnabledConverter}}"/>
<ToggleButton Visibility="{Binding Path=C.Count, Converter={StaticResource ComboBoxItemCountToVisibilityConverter}}"/>
</StackPanel>

Related

how to disable a button when a textbox becomes readonly?

I have a button and text box inside a stackpanel, when text box gets readonly state then the button should disable, i want to do this in XAML only is there any way to do this?
The binding is easy to define but you need a converter to invert the boolean value. Since you want to enable (IsEnabled = true) the Button when the TextBox is not readonly (IsReadOnly = false).
XAML
<StackPanel>
<StackPanel.Resources>
<local:InvertBooleanConverter x:Name="invertBoolConverter"/>
</StackPanel.Resources>
<TextBox x:Name=textBox />
<Button IsEnabled={Binding IsReadOnly, ElementName=textBox, Converter={StaticResource invertBoolConverter}}/>
</StackPanel>
local is a namespace you define in your UserControl that points to the namespace of the InvertBooleanConverter
xmlns:local="clr-namespace:NamespaceOfTheInvertBooleanConverter"
Converter
public class InvertBooleanConverter: IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
bool currentValue = System.Convert.ToBoolean(value);
return !currentValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
bool currentValue = System.Convert.ToBoolean(value);
return !currentValue;
}
}
<StackPanel>
<TextBox x:Name="targetTB">Hello</TextBox>
<Button Content="Test Button">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=targetTB, Path=IsReadOnly}" Value="True">
<Setter Property="Button.IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=targetTB, Path=IsReadOnly}" Value="False">
<Setter Property="Button.IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
try this, it can work as you need.

Select control style by binding value

I have an editor view that can be used for multiple edited objects. The view model for multiple objects provides a property like Field1Multiple of type bool for each field that needs to be handled. In this case, it's only ComboBox controls for now. Whenever multiple differing values shall be indicated for that field, a certain style should be applied to that control which is defined in App.xaml. That style changes the background of the control to visualise that there is no single value that can be displayed here.
I've tried with this XAML code:
<ComboBox
ItemsSource="{Binding Project.Field1Values}" DisplayMemberPath="DisplayName"
SelectedItem="{Binding Field1}">
<ComboBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Field1Multiple}" Value="true">
<Setter
Property="ComboBox.Style"
Value="{StaticResource MultiValueCombo}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
But it doesn't work because I cannot set the Style property from inside a Style. If I use triggers directly on the control, there may only be EventTriggers, no DataTriggers, the compiler says.
How can I set the control's style based on a binding value? Or, how can I set a certain style for a control if a binding value is true?
(EDIT to full solution)
You can use converter:
public class AnyIsMultipleToStyle : IValueConverter
{
public Style NormalStyle { get; set; }
public Style MultiStyle { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
IList<SampleClass> list= value as IList<SampleClass>;
if (list!=null)
{
if (list.Any(i => i.Multi))
return MultiStyle;
}
}
return NormalStyle;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And in your xaml:(You indicate normal style and multistyle to converter)
<Window.Resources>
<Style x:Key="MultiValueCombo" TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="Olive" />
</Style>
<Style x:Key="NormalCombo" TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="Red" />
</Style>
<my:AnyIsMultipleToStyle x:Key="AnyIsMultipleToStyle1" MultiStyle="{StaticResource MultiValueCombo}" NormalStyle="{StaticResource NormalCombo }" />
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding Items, ElementName=root}" >
<ComboBox.Style>
<Binding Converter="{StaticResource AnyIsMultipleToStyle1}" Path="Items" ElementName="root" >
</Binding>
</ComboBox.Style>
</ComboBox>
</Grid>

WPF Progress bar

WPF: I have a Problem in Progressbar i want it to show when the operation is not finished and when my operation is finished it will hide. Please show me understandable example so i can apply it to my work. Thanks in advance!
you can do that in different scenarios.
using triggers, (I'd prefer that)
<ProgressBar Maximum="100" Margin="10,107,232,168" Value="0" Name="progr">
<ProgressBar.Resources>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Value}" Value="100">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Resources>
</ProgressBar>
Using converters
<Grid>
<Grid.Resources>
<delWpf:VisibilityConverter x:Key="conv"/>
</Grid.Resources>
<ProgressBar Name="prog2" Minimum="0" Maximum="100"
Value="{Binding CurrentIndex, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding RelativeSource={RelativeSource Self}, Path=Value, Mode=OneWay, Converter={StaticResource conv}}" />
</Grid>
and converter
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Math.Abs((double)value - 100) < 0.001 ? Visibility.Hidden : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You might use Extended WPF Toolkit which has a BusyIndicator control,
http://wpftoolkit.codeplex.com/wikipage?title=BusyIndicator
Samples are included in the download.
For your information, Microsoft introduces BusyIndicator in Silverlight first (but fails to ship one for WPF) as a replacement of progress bar.

Enable TextBox when ListViewItem is selected in WPF (databinding)

How can i enable/disable a TextBox with DataBinding in WPF when a ListViewItem is (not) selected?
I have created a converter class:
public class BoolConvert : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
and added the property to the TextBox:
IsEnabled="{Binding SelectedItem, ElementName=listViewCards, Converter={StaticResource BoolConvert}}"
but i have a XamlParseException becouse he can´t find the class :-(
You could alternately use a style trigger on the TextBox, eliminating the need for a ValueConverter:
<TextBox>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lvItems, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<ListView Name="lvItems" .../>
You can bind the IsEnabled property on the TextBox to the SelectedItem property on the ListView. Then you'll need a converter (an implementation of IValueConverter) to convert selected values into boolean values.
<TextBox IsEnabled="{Binding SelectedItem, ElementName=listView, Converter={StaticResource MyConverter}}"/>
<ListView x:Name="listView" .../>
Then, in your converter:
public object Convert(object value, ...)
{
return value == null;
}
ListViewItem in ListView :
Enable if Selected.
Try the following:
<ListViewItem Margin="5" Background="AliceBlue">
<TextBox Margin="5" Text="Lösung SECHS"
IsEnabled="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}"/>
</ListViewItem>

WPF Data Binding and Formatting

I have a bool property in my ViewModel called IsConnected and I would like to bind it to a TextBlock in my MainWindow. Rather than have the textblock read true or false I need it to say Connected or Disconnected instead. Forgive me because I'm new to WPF. If someone could give me a head start I can take it from there but I'm not sure how to figure out what I need.
Easiest way is probably to create a custom converter which converts your bool value to a string. Search anywhere for IValueConverter and/or WPF.
public class BoolToConnectedConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if((bool)value)
return "Connected";
else
return "Disconnected";
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
add xmlns:
xmlns:converter="clr-namespace:MyProjectNameSpace"
add resource to XAML (change to whatever element needed)
<Window.Resources>
<converter:BoolToConnectedConverter x:Key="connectedConverter" />
</Window.Resources>
in XAML:
<TextBlock Text={Binding IsConnected, Converter={StaticResource connectedConverter}" />
I'd generally prefer to just add a property to the view model (I really dislike value converters), but here's a simple way to accomplish what you're trying to do using a style:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Connected"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsConnected}" Value="False">
<Setter Property="Text" Value="Disconnected"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Edit
Note that once you get used to using data triggers, you can make all kinds of modifications to your view without touching your view model. For instance:
<StackPanel>
<Image Source="images\connected.png">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsConnected}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Image Source="images\disconnected.png">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsConnected}" Value="False">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
Using ViewModel, you write two property wrap, and notify changes in the real property.
So that whenever the value is changed, you the string representation will update and bind to controls, while you can still use the bool property in the code.
public string IsConnectedStr{
get{
return IsConnected?"Connected":"Disconnected";
}
}
public bool IsConnected{
get{
return _isConnected;
}
set{
_isConnected=value;
PropertyChanged("IsConnected");
PropertyChanged("IsConnectedStr");
}
}
You could do this in two ways
1) Write a converter
2) Change the function in the ViewModel so that it returns the desired string instead of a bool
The easiest way is #2, but if you really need the bool value somewhere else in your code you go with #1 (google converter and wpf)
Take a look at value converters.
http://www.wpftutorial.net/ValueConverters.html
public class BoolToConnectedConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var isConnected = (bool)value;
return isConnected ? "Connected" : "Disconnected";
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException("Not required for read-only values");
}
}
In your XAML:
<Window.Resources>
<l:BoolToConnectedConverter x:Key="boolToConnectedConverter" />
</Window.Resources>
<Grid>
<Label Content="{Binding IsConnected, Converter={StaticResource boolToConnectedConverter}}" />
</Grid>

Resources