How to pass element in the converter parameter in uwp? - c#

I have to pass the element in the converter parameter in UWP as like below WPF code snippet.
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource captionSummaryRowConverter}, ConverterParameter= {x:Reference Name= dataGrid}}" Foreground="Blue" Background="Yellow" FontSize="15"></TextBlock>
</DataTemplate>
Since x:Reference keyword is not available in the Uwp, Is there any possible way to pass the element to converterparameter in uwp.

How to pass element in the converter parameter in uwp?
Currently, Converter does not support pass element ConverterParameter. We often use it to pass StaticResource or string format.
<TextBlock Text="{Binding DoubleValue,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:N2}'}"/>
OR
<TextBlock Text="Score : 60" Foreground="{Binding Passed,Converter={StaticResource BoolToValueConverter},ConverterParameter={StaticResource PassedBrush},FallbackValue={StaticResource FailedBrush}}"/>
Update
You could add the property to the Converter and bind with your root panel, then pass the element name as parameter to the Converter, call FindName method to get the element.
public class ImageConverter : IValueConverter
{
public UIElement UIParameter { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
var rootGrid = UIParameter as Grid;
if(parameter != null)
{
var ele = rootGrid.FindName(parameter.ToString());
}
return value;
}
}
Usage
<local:ImageConverter x:Key="ImageConverter" UIParameter="{x:Bind RootGrid}" />
</Page.Resources>
<Grid x:Name="RootGrid">
<TextBlock x:Name="TestBlock" Text="Hello" />
<Image Source="{Binding Converter={StaticResource ImageConverter}, ConverterParameter='TestBlock'}" />
<ComboBox

Related

WPF bind enum to combobox

In my WPF UserControl I need to bind an Enum on a ComboBox. This enum is declared locally:
public partial class ViewerDataConfiguration : UserControl
{
private ViewerDataConfigurationViewModel PageViewModel;
public Visibility IsParametriSelected { get; set; }
public IEnumerable<eDatoAlarmMode> EnumAlarmModes {
get
{
return Enum.GetValues(typeof(eDatoAlarmMode)).Cast<eDatoAlarmMode>();
}
}
On the main Grid, where there is a collection bound, I defined a ComboBox as follows:
<TextBox Grid.Column="16" Text="{Binding ConfigObject.Edit.Source}" Style="{StaticResource txtDataStyle2}" Width="30" Visibility="{Binding ConfigObject.Edit, Converter={StaticResource ListaValoriVisibilityConverter}}" HorizontalAlignment="Stretch" TextChanged="Data_TextChanged" />
<Label Grid.Column="17" Content="AlarmMode" Style="{StaticResource labelStyle2}" />
<ComboBox Grid.Column="18" Width="30"
ItemsSource="{Binding Path=EnumAlarmModes, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:ViewerDataConfiguration}}"
DisplayMemberPath="Value"
SelectedValuePath="Value" Style="{StaticResource comboUsersStyle}" />
Basically seems that my IEnumerable is not bound correctly. I see the elements but they're blank. Any hint?
You are using DisplayMemberPath and SelectedValuePath attributes, but your collection item type is just a simple string, and want to use this entire instance directly, so you should remove these attributes and it should work as expected.
You also need to change the field to a property as data binding works only on properties, not class fields (although x:Bind in UWP no longer has this limitation):
public IEnumerable<AlarmMode> EnumAlarmModes
{
get
{
return Enum.GetValues(typeof(AlarmMode)).Cast<AlarmMode>();
}
}
If you want to display enum values instead of names, create a value converter:
public class EnumValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then use it in the ItemTemplate:
<ComboBox Grid.Column="18" Width="100"
ItemsSource="{Binding Path=EnumAlarmModes}">
<ComboBox.Resources>
<local:EnumValueConverter x:Key="EnumValueConverter" />
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumValueConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
For this to work you also have to add a xmlns:local declaration to your Window:
xmlns:local="clr-namespace:NamespaceOfConverter"

Using a IConverter to deal with {NewItemPlaceholder} in WPF / XAML / MVVM

Here is my DataTemplate:
<UserControl.Resources>
<converter:PlaceholderConverter x:Key="_placeholderConverter"/>
<!-- Data(Display)Template for data objects of x:Type Customer-->
<DataTemplate DataType="{x:Type model:Customer}">
<!-- Customer Properties will be vertically stacked -->
<ContentControl >
<StackPanel>
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text="{Binding Phone}"/>
</StackPanel>
</ContentControl>
</DataTemplate>
<UserControl.Resources>
And the two different 'container's:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="Delete"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="75"
Command="{Binding DeleteCommand}"/>
<DataGrid Grid.Row="1"
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"
AutoGenerateColumns="True"/>
<ListBox
Grid.Row="2"
ItemsSource="{Binding Customers, Mode=OneWay}"/>
</Grid>
And the app:
How to remove the {NewItemPlaceholder}? [Done, solution below].
How to prevent the binding error that mention "{NewItemPlaceholder}" when clicking in one of the empty rows in the table above intending on adding a new row (I can still add rows).
The errors:
...Cannot convert '{NewItemPlaceholder}' from type 'NamedObject' to type 'CustomerExample.Model.Customer'...
...ConvertBack cannot convert value '{NewItemPlaceholder}' (type 'NamedObject'). BindingExpression:Path=SelectedCustomer; DataItem='CustomerViewModel'...
I can write an IConverter implementation, but how to tie it in to the XAML?
thanks in advance :-)
Here is the implementation of the IConverter:
public class PlaceholderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value.ToString() == "{NewItemPlaceholder}")
return DependencyProperty.UnsetValue;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
and to bind to individual items, the XAML goes something like:
<TextBlock Text="{Binding Name, Converter={StaticResource PlaceholderConverter}}"/>
But I think I need to add it 'globally' to the data collection elements, not to where individual properties are being bound.
You don't need a Binding Converter. Instead, bind the ListBox to a CollectionViewSource that wraps the Custumers collection. The CollectionViewSource skips the NewItemPlaceholder element from the source collection.
<UserControl.Resources>
...
<CollectionViewSource x:Key="CustomersCVS" Source="{Binding Customers}"/>
</UserControl.Resources>
...
<ListBox ItemsSource="{Binding Source={StaticResource CustomersCVS}}"/>
You also don't need a Converter for the SelectedItem Binding. Just set the Binding's TargetNullValue property:
<DataGrid SelectedItem="{Binding SelectedCustomer,
TargetNullValue={x:Static CollectionView.NewItemPlaceholder}}" .../>
Even though the accepted answer is correct for the OP's question I needed a more general approach to prevent the error and still allow users to add rows. As I used this ValueConverter for many different object types I used reflection to determine the target type's constructor and just returned a new object of that type.
public class IgnoreNewItemPlaceHolderConverter : IValueConverter
{
private const string NewItemPlaceholderName = "{NewItemPlaceholder}";
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == DependencyProperty.UnsetValue)
return DependencyProperty.UnsetValue;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.ToString() == NewItemPlaceholderName)
{
var ctors = targetType.GetConstructors();
// invoke the first public constructor with no parameters.
return ctors[0].Invoke(new object[] { });
}
return value;
}
}

Using ObjectDataProvider inside HierarchicalDataTemplate

I want to add items of my class treeviewitem to a TreeView.
And I want to bind the ItemSource of this TreeViewItem to a method of itself !
I am trying to use the ObjectDataProvider for this.. See my XAML:
<Grid Background="#FFE5E5E5">
<Grid.Resources>
<HierarchicalDataTemplate DataType="{x:Type myNs:treeviewitem}">
<HierarchicalDataTemplate.Resources>
<ObjectDataProvider x:Key="getItems"
MethodName="GetItems"
ObjectInstance="{Binding RelativeSource={RelativeSource Self}}" />
</HierarchicalDataTemplate.Resources>
<HierarchicalDataTemplate.ItemsSource>
<Binding Source="{StaticResource getItems}" />
</HierarchicalDataTemplate.ItemsSource>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0"
Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Grid.Resources>
<TreeView x:Name="guiTreeview"
HorizontalAlignment="Left"
Width="200" />
</Grid>
But binding to an ObjectInstance isnt possible!
How is it possible to get the current object instance "into" the ObjectDataProvider?
What would be the right way of doint this?
And NO, its not possible to use a Property ..
I have done it now with a ValueConverter.
XAML:
<Grid Background="#FFE5E5E5">
<Grid.Resources>
<HierarchicalDataTemplate DataType="{x:Type myNs:MyItem}" ItemsSource="{Binding RelativeSource={RelativeSource Self}, Converter={myNs:GetItemsConverter}}" >
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0" Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Grid.Resources>
<TreeView x:Name="guiTreeview" HorizontalAlignment="Left" Width="200" />
</Grid>
Converter:
public abstract class BaseConverter : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
public class GetItemsConverter : BaseConverter, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var tvi = value as TreeViewItem;
if (tvi == null) return null;
var myitem = tvi.DataContext as MyItem;
if (myitem == null) return null;
return myitem.GetItems();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}

WPF binding from parent to child element

Here is my XAML
<ListView x:Name="missingVariablesListView" ScrollViewer.CanContentScroll="True" HorizontalAlignment="Left" Height="320" Margin="81,28,0,0" VerticalAlignment="Top" Width="641" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="ComponentID: " FontWeight="Bold" Foreground="Brown" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Variable Name: " Foreground="Green"/>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text=" "/>
<TextBlock Text="Variable Value: " Foreground="Blue"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style >
<Style.Triggers>
<DataTrigger Binding="{Binding IsMissing}" Value="false">
<Setter Property="UIElement.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<TextBlock Text="-----------------------------------------------------------------"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is the CodeBehind
this.missingVariablesListView.DataContext = //Code to fill in the list View
Classes Involved
public class Component
{
private ObservableCollection<ComponentParameter> parameters = new ObservableCollection<ComponentParameter>();
public string Name
{
get;
set;
}
public ObservableCollection<ComponentParameter> Parameters
{
get{return parameters;}
set{parameters = value;}
}
}
public class ComponentParameter
{
public string Name
{
get;set;
}
public string Value
{
get;set;
}
public bool HasErrors
{
get;
set;
}
public bool IsMissing
{
get;set;
}
Sample Output (at the moment)
ComponentID: Component1
--------------------------
ComponentID: Component2
VariableName:Var1 Variable Value:Val1
VariableName:Var2 Variable Value:Val2
-----------------------
ComponentID: Component3
-----------------------
ComponentID: Component4
-----------------------
What i want to do is that whenever the boolean IsMissing is true for the inner element within the itemsControl i want to make sure that the ComponentID and the Name properties within the StackPanel (that has the orientation as horizontal) are not shown in the window including the child elements. Basically i am trying to find a way to exclude the whole description for that particular ComponentID whose isMissing variable is set to true. Any suggestions on this?
I would consider to add a property IsAnyParameterMissing to the Component class:
public class Component
{
private ObservableCollection<ComponentParameter> parameters = new ObservableCollection<ComponentParameter>();
public string Name
{
get;
set;
}
public ObservableCollection<ComponentParameter> Parameters
{
get{return parameters;}
set{parameters = value;}
}
public bool IsAnyParameterMissing
{
get { return this.Parameters.Any(param => param.IsMissing); }
}
}
And then bind the visibility to this property:
<StackPanel Orientation="Horizontal" Visibility="{Binding IsAnyParameterMissing, Converter={BooleanToVisibilityConverter}}">
<TextBlock Text="ComponentID: " FontWeight="Bold" Foreground="Brown" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
This will only display the StackPanel if any of the Parameters in the collection has its IsMissing property equal to true. Note that this will not change the visibility if the IsMissing property is changed for any of the items! This would need some additional work.
EDIT: Note that the {BooleanToVisibilityConverter} might need to be adjusted, depending on your available converters. Should be a simple task though.
One thing i noticed is that you don't implement the properties (such as "isMissing") as DependencyProperty. Neither do you use property change notifications via INotifyPropertyChanged.
You have to implement either of the two, otherwise changes of the properties will not be propagated through the bindings. That means, the trigger wouldn't trigger...
You could use a BooleanToVisibilityConverter to hide those items for you, although you may need to change your property or add a new IsPresent property for this:
In Resources:
<Converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"
IsInverted="True" />
In your ListView.ItemTemplate:
<StackPanel Orientation="Horizontal" Visibility="{Binding IsMissing, Converter={
StaticResource BoolToVisibilityConverter}}">
<TextBlock Text="ComponentID: " FontWeight="Bold" Foreground="Brown" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
Custom BoolToVisibilityConverter with IsInverted property:
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
public bool IsInverted { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.GetType() != typeof(bool)) return null;
bool boolValue = IsInverted ? !(bool)value : (bool)value;
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.GetType() != typeof(Visibility)) return null;
if (IsInverted) return (Visibility)value != Visibility.Visible;
return (Visibility)value == Visibility.Visible;
}
}
Now it will just take you one minute to implement it. I have updated the XAML example above to use it.

How to get Image and text from RSS file in WP7?

I am trying to get RSS text with its Image but image couldn't show i would view model for getting image and use simple RSS technique to get image would you tell me how to get both image and text.......
Here is my XAML code:
<ListBox Name="lstRSS" ItemsSource="{Binding FeedItems}" DataContext="{StaticResource MainViewModel}" FontSize="30" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="700">
<TextBlock Text="{Binding Path=Title}"></TextBlock>
<UserControls:Loader Width="100" Height="100" />
<Image Source="{Binding Link}" Width="450" Height="350" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
You cannot bind to a URL in that way as a String/Uri is not a valid value for the Image.Source property. If a constant URL is set in xaml then the image will be shown correctly as the compiler generated code takes the URL and converts it to a BitmapSource.
To bind an image URL in that fashion you will need a converter. The converter can take the URL and convert it to a BitmapImage:
public class UriToImageConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// This could be extended to accept a Uri as well
string url = value as string;
if (!string.IsNullOrEmpty(url))
{
return new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute));
}
else
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
You then need to add an instance of this class to the apps resources (in app.xaml or in the page xaml):
<local:UriToImageConverter x:Key="ImageConverter"/>
You can then set the binding like this:
<Image Source="{Binding Link, Converter={StaticResource ImageConverter}}" />

Categories