I am incredibly new to working with UWP. I apologize if this is something basic.
I'm going through some of the samples provided by Microsoft on GitHub. ( https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlListView )
What I'm attempting to do, is to use the XAML ListView example, but apply some conditional formatting to the list if a condition is met. Such as if Contact.Position == "Developer", change the color of the text to green.
The solution I found in the link below looked promising, however, the style triggers using in WPF are not available in UWP .
Conditional formating of a TextBlock within a Listbox’s DataTemplate
The XAML generated for each item in the listView is defined as:
<DataTemplate x:Name="SpectraListViewTemplate" x:DataType="data:spectraClass">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="Ellipse"
Grid.RowSpan="2"
Width ="32"
Height="32"
Margin="6"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Fill="LightGray"/>
<TextBlock Grid.RowSpan="2"
Width="{Binding ElementName=Ellipse, Path=Width}"
Height="{Binding ElementName=Ellipse, Path=Height}"
Margin="6"
Foreground="{ThemeResource ApplicationPageBackgroundThemeBrush}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{x:Bind Id}"
x:Phase="1"/>
<TextBlock x:Name="SpectraListViewTemplateNameTextBox"
Grid.Column="1"
Text="{x:Bind Name}"
x:Phase="1"
Style="{ThemeResource BaseTextBlockStyle}"
Margin="12,6,0,0"/>
<TextBlock Grid.Column="1"
Grid.Row="1"
Text="{x:Bind Date}"
x:Phase="2"
Style="{ThemeResource BodyTextBlockStyle}"
Margin="12,0,0,6"/>
</Grid>
</DataTemplate>
Does anyone have some advice or a direction I should be looking?
You could use IValueConverter to achieve this.
Code:
//Add the below code in your references in xaml
xmlns:converters="using:MyProject.Converter"
//Add this part to the resources in the page
<Page.Resources>
<converters:PersonToColorConverter x:Key="PersonToColorConverter" />
</Page.Resources>
//This could be a part of your ListView DataTemplate.
<TextBlock Text="Hello" Foreground="{Binding Position,Converter{StaticResource PersonToColorConverter}}" />
Now create a converter class called PersonToColorConverter and use the below code.
public class PersonToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
SolidColorBrush brush = new SolidColorBrush();
string personPosition = value.ToString();
if(personPosition!=null && personPosition.Equals("Developer"))
{
brush.Color = Colors.Green;
}
else
{
brush.Color = Colors.White;
}
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return new NotImplementedException();
}
}
Related
I have a wpf window with a grid. I would like to hide rows and I do with this code as shown in other stackoverflow threads:
buttonsGrid.Visibility = Visibility.Collapsed; or buttonsGrid.Height = 0;
dayTimePicker.Visibility = Visibility.Collapsed; or dayTimePicker.Height = 0;
Set Visibility to Collapsed or Height to 0 gives the same effect, but I would like the white space occupied by these Rows to sweep ... I would like the whole window to be occupied by the indexed row 0. .. How can I do it?
This is my window:
<Window x:Class="PerformanceVideoRec.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:DTControl="clr-namespace:DayTimePickControl"
Title="{StaticResource ID_TITLE}" Height="600" Width="900" Loaded="Window_Loaded"> <!--Closing="Window_Closing"> -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" x:Name="ControlPart" IsEnabled="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="LeftGrid">
<Grid.RowDefinitions>
<RowDefinition Height="55*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<WindowsFormsHost Grid.Row="0" Margin="5" Background="Gray">
<wf:PictureBox x:Name="playWindow"></wf:PictureBox>
</WindowsFormsHost>
<UniformGrid Grid.Row="1">
<Button x:Name="btnShowHideControls" Content="Nascondi Controlli" Click="btnShowHideControls_Click"/>
</UniformGrid>
<UniformGrid Columns="6" Grid.Row="2" x:Name="buttonsGrid">
<Button x:Name="btnPause" Margin="5" Width="50" Content="{StaticResource ID_PAUSE}" Click="btnPause_Click"></Button>
<Button x:Name="btnPlay" Margin="5" Width="50" Content="{StaticResource ID_PLAY}" Click="btnPlay_Click" Visibility="Collapsed"/>
<Button x:Name="btnStop" Margin="5" Width="50" Content="{StaticResource ID_STOP}" Click="btnStop_Click"></Button>
<Button x:Name="btnSlow" Margin="5" Width="50" Content="{StaticResource ID_SLOW}" Click="btnSlow_Click"></Button>
<TextBox x:Name="tbSpeed" IsEnabled="False" Width="50" Height="25" TextAlignment="Center" VerticalContentAlignment="Center" Text="1X" />
<Button x:Name="btnFast" Margin="5" Width="50" Content="{StaticResource ID_FAST}" Click="btnFast_Click"></Button>
<Button x:Name="btnNormal" Margin="5" Width="50" Content="{StaticResource ID_NORMAL}" Click="btnNormal_Click"></Button>
</UniformGrid>
<DTControl:DayTimePick x:Name="dayTimePicker" Grid.Row="3" Width="550" Height="100" Grid.RowSpan="2" OnTimeClick="dayTimePicker_OnTimeClick"></DTControl:DayTimePick>
</Grid>
<Frame x:Name="PlayBackFrame" Grid.Column="1" Background="AliceBlue" ></Frame>
</Grid>
</Grid>
The MVVM way:
make a separate view model for the part of UI you want to collapse. Let's call it PlayViewModel,
make a DataTemplate for it,
expose it as a property (e.g. let's call it Play, don't forget to raise property change event) in the view model which is a DataContext for the whole view
you display it in your grid with ContentPresenter, ContentPresenter.Content bound to Play property
you do hiding by null-ing Play property, you show it by restoring it.
You get testability for free.
You could use Data Binding and bind the the property Visibility of the control inside the row you want to collapse with a converter.
I usually use the NuGet package Mvvm Light, documentation to have some facilities while using Data Binding. (In this case RelayCommand, RaisePropertyChanged implementation)
A very basic example:
Part of the view. Here you can notice the Binding between the Visibility property of the button and the property IsButton1Visible of the ViewModel. Of course bool and Visibility aren't the same type, so I had to create a mapping using an IValueConverter:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="1" Visibility="{Binding IsButton1Visible, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Grid.Row="1" Content="2" />
<Button Grid.Row="2" Content="3" />
<Button Grid.Row="3" Content="4" />
<Button Grid.Row="4" Content="Toggle button 1 visibility" Command="{Binding ToggleButton1Visibility}" />
</Grid>
The window's constructor in the code behind (you could also bind the ViewModel via the DataContext property directly into the View), used to associate the View with the ViewModel:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyWindowViewModel();
}
The converter to convert true to Visibility.Visible:
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> (bool)value ? Visibility.Visible : Visibility.Collapsed;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
App.xaml, Application.Resource part, used to make the View "see" the converter:
<Application.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Application.Resources>
The ViewModel. Here RaisePropertyChanged of set method of IsButton1Visible is very important because it notifies the View that the property is changed, so that the View can refresh itself:
public class MyWindowViewModel : ViewModelBase
{
private bool _isButton1Visibile = true;
public bool IsButton1Visible
{
get => _isButton1Visibile;
set
{
if (_isButton1Visibile == value)
return;
_isButton1Visibile = value;
RaisePropertyChanged(nameof(IsButton1Visible));
}
}
RelayCommand _toggleButton1Visbility;
public RelayCommand ToggleButton1Visibility
{
get
{
return _toggleButton1Visbility ?? (_toggleButton1Visbility = new RelayCommand(
() =>
{
IsButton1Visible = !IsButton1Visible;
}));
}
}
}
LeftGrid.RowDefinitions[2].Height = new GridLength(0);
LeftGrid.RowDefinitions[3].Height = new GridLength(0);
If you want to restore make this
LeftGrid.RowDefinitions[2].Height = new GridLength(5, GridUnitType.Star);
LeftGrid.RowDefinitions[3].Height = new GridLength(20, GridUnitType.Star);
In my WPF Application I have a two textblocks which get filled from the code behind with a run. Every second line should have a different background color so it gets easier to read. Unfortunately, the lines are only dyed as far as they are written. But I want the background color to go over the entire line and not just the written area.
Code:
for (int i = 0; i < GlobalSettings.prefixList.Count; i++)
{
runLeft = new Run(GlobalSettings.prefixList[i].prefix + "\n");
runRight = new Run(GlobalSettings.prefixList[i].amount + "\n");
if (i % 2 == 0)
{
runLeft.Background = Brushes.Gray;
runRight.Background = Brushes.Gray;
}
else
{
runLeft.Background = Brushes.LightGray;
runRight.Background = Brushes.LightGray;
}
tblock_StatisticsLeft.Inlines.Add(runLeft);
tblock_StatisticsRight.Inlines.Add(runRight);
}
Example Picture
The two textblocks are seamlessly together in the middle so it would look like it is a single line in a single textblock. The spaces between the lines are negligible if this makes it easier.
Is there a solution without using a textbox or richtextbox?
EDIT:
XAML Code:
<UserControl x:Class="MuseKeyGenApp.UCStartUp"
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:MuseKeyGenApp"
mc:Ignorable="d"
Background = "#FF0069B4"
d:DesignHeight="500" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="26"/>
<RowDefinition Height="0"/>
<RowDefinition Height="*" MinHeight="80"/>
<RowDefinition Height="*" MinHeight="80"/>
<RowDefinition Height="*" MinHeight="80"/>
<RowDefinition Height="*" MinHeight="80"/>
<RowDefinition Height="*" MinHeight="80"/>
<RowDefinition Height="0"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="150"/>
<ColumnDefinition Width="0.75*" MinWidth="100"/>
<ColumnDefinition Width="0.75*" MinWidth="100"/>
<ColumnDefinition Width="0.75*" MinWidth="100"/>
<ColumnDefinition Width="0.75*" MinWidth="100"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="10,35,12,12" Name="sv_PrefixList">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="tblock_StatisticsLeft" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,0,0" Text="TextBlock" VerticalAlignment="Stretch" TextAlignment="Left"/>
<TextBlock Grid.Column="1" x:Name="tblock_StatisticsRight" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,10,0" Text="TextBlock" VerticalAlignment="Stretch" TextAlignment="Right"/>
</Grid>
</ScrollViewer>
</Grid>
I left out all the other stuff of the control that is not relevant.
You could (should) use an ItemsControl. Set the ItemsSource property of it to your GlobalSettings.prefixList collection, i.e. you replace your for loop with this:
ic.ItemsSource = GlobalSettings.prefixList;
Make sure that "prefix" and "amount" are public properties (and not fields) of your "prefix" type or whatever you call it:
public string prefix { get; set; }
You then put the Grid with the TextBlocks in the ItemTemplate of the ItemsControl and bind the TextBlocks to the "prefix" and "amount" properties:
<ScrollViewer Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="10,35,12,12" Name="sv_PrefixList">
<ItemsControl x:Name="ic" AlternationCount="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="tblock_StatisticsLeft" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,0,0" VerticalAlignment="Stretch" TextAlignment="Left"
Text="{Binding prefix}"/>
<TextBlock Grid.Column="1" x:Name="tblock_StatisticsRight" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,10,0" VerticalAlignment="Stretch" TextAlignment="Right"
Text="{Binding amount}"/>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Gray" TargetName="grid"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray" TargetName="grid"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
This should get you coloured lines.
Here is the correct way of doing this:
Xaml:
<Window.Resources>
<local:BackConverter x:Key="BackConverter"/>
</Window.Resources>
<Grid Margin="10">
<ItemsControl Name="ic">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="False">
<DockPanel.Background>
<MultiBinding Converter="{StaticResource BackConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}"/>
</MultiBinding>
</DockPanel.Background>
<TextBlock DockPanel.Dock="Left" Text="{Binding Left}">
</TextBlock>
<TextBlock DockPanel.Dock="Right" Text="{Binding Right}">
</TextBlock>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
c# code:
public class obj
{
public string Left { get; set; }
public string Right { get; set; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
List<obj> objects = new List<obj>();
for (int i = 0; i < 10; i++)
{
var left = "aaaaa";
var right = "bbbbb";
objects.Add(new obj() { Left = left, Right = right });
}
ic.ItemsSource = objects;
}
the converter:
public class BackConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var index = ((ItemsControl)values[1]).Items.IndexOf(values[0]);
if (index % 2 == 0)
return Brushes.Gray;
return Brushes.White;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
As per title. The column is in a DataTemplate.
This is what I have currently:
var test = FindChildControl<ComboBox>(this, "PrintCode") as ComboBox;
test.ItemsSource = listPrintCode;
MessageBox.Show(test.Items.Count.ToString());
FindChildControl method:
private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
var fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return child;
}
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
return null;
}
XAML - Template
<DataTemplate x:Key="lbCommsItemSetTemplate">
<Grid Margin="0" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" />
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="Blue" Margin="40,0,0,0"
Text="{Binding CommonDesc}" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Serial:" Margin="0,0,0,0"/>
<TextBlock Grid.Row="1" Grid.Column="0" Foreground="Blue" Margin="35,0,0,0"
Text="{Binding Serial}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="lbIssueTemplate">
<Grid Margin="0" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" />
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="Blue" Margin="50,0,0,0"
Text="{Binding CommonDesc}" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="Qty:" Margin="10,0,0,0"/>
<TextBox Grid.Row="0" Grid.Column="1" Foreground="Blue" Margin="35,0,0,0"
Text="{Binding LoanQty}" PreviewTextInput="UIElement_OnPreviewTextInput" MaxLength="4"
GotKeyboardFocus="UIElement_OnGotKeyboardFocus" MaxLines="1"/>
<ComboBox x:Name="PrintCode" Grid.Row="0" Grid.Column="2" ItemsSource="{Binding}"
SelectedValuePath="PrintCode" DisplayMemberPath="PrintCode"/>
<CheckBox Grid.Row="0" Grid.Column="3" IsChecked="{Binding PrintShortSerial}"/>
</Grid>
</DataTemplate>
XAML - ListBox that implements the Template
<telerik:RadListBox Grid.Row="0" Grid.Column="2" Margin="0, 5, 5, 5"
x:Name="listBoxIssue" HorizontalAlignment="Left" VerticalAlignment="Top"
Height="690" Width="793"
ItemTemplate="{StaticResource lbIssueTemplate}" ItemsSource="{Binding}"
SelectionMode="Multiple" Drop="ListBoxIssue_OnDrop"/>
The message box is just simply to confirm that 'listPrintCode' and 'FindChildControl' is working as intended. But the ComboBox didn't display anything, even if it's just 1 ComboBox. If I apply the codes to a normal ComboBox not part of the template, it's all fine. I think there's an obvious flaw in my code, which is that there's nothing that seems to apply to all ComboBoxes in the column. So my question is, how do I bind my ItemsSource as the column of the comboboxes?
Note: The number of rows (ComboBoxes) are not fixed.
I have PivotPage with some PivotItems each with an own LongListSelector:
<phone:PivotItem x:Name="pivotitem1" Header="Headline 1">
... same like in pivotitem2 ...
</phone:PivotItem>
<phone:PivotItem x:Name="pivotitem2" Header="Headline 2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<phone:LongListSelector x:Name="lst2" Margin="12,0,0,0" ItemTemplate="{StaticResource myLocationsListTemplate}" ItemsSource="{Binding Items}">
</phone:LongListSelector>
</Grid>
</phone:PivotItem>
<phone:PivotItem x:Name="pivotitem3" Header="Headline 3">
... same like in pivotitem2 ...
</phone:PivotItem>
All LongListSelector are using same DataTemplate, so I declared it globally as StaticRessource.
<DataTemplate x:Name="myLocationsListTemplate">
<Button Click="btn_ShowLocationDetails_Click" Tag="{Binding ID}" Style="{StaticResource mBlankButton}" Margin="1,0,-1,0">
<StackPanel Margin="0,0,0,15" >
<Grid VerticalAlignment="Top" Margin="0,0,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" TextTrimming="WordEllipsis" Text="{Binding Name}" TextWrapping="NoWrap" Style="{StaticResource PhoneTextLargeStyle}" VerticalAlignment="Top" Margin="0,0,0,22" />
<Image Grid.Column="0" Width="138" Height="25" Source="/mAppData/stars-3.png" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0"/>
<TextBlock Grid.Column="1" Text="{Binding DistanceInMeterFormatted, FallbackValue=fallback, TargetNullValue=nullvalue, Mode=OneWay}" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right" Margin="0,0,-3,20" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text="{Binding LastUploadAgo}" TextWrapping="NoWrap" Margin="0" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
<Grid VerticalAlignment="Top" Margin="0,10,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Width="100" Height="100" Source="{Binding PreviewImg1}"/>
<Image Grid.Column="1" Width="100" Height="100" Source="{Binding PreviewImg2}"/>
<Image Grid.Column="2" Width="100" Height="100" Source="{Binding PreviewImg3}"/>
<Image Grid.Column="3" Width="100" Height="100" Source="{Binding PreviewImg4}"/>
</Grid>
</StackPanel>
</Button>
</DataTemplate>
In in OnNavigateTo I give to a corresponding model. I apply the model by code :
pivotitem1.DataContext = ...
pivotitem2.DataContext = App.ViewSurroundingsData;
pivotitem3.DataContext = ...
In App.ViewSourroundingsData is my ObservableCollection globally stored.
The collection contains a list of object with a lot of properties. One specific property is an integer: imgcnt - it holds the amount of images.
Now I want to make all list entries invisible when imgcnt is 0.
I researched, that I could use a ValuesConverter. But I don´t know how to code this with a depedency to my integer value in the class property. I can´t extend the solution found on Updating IValueConverter through code.
I don´t know how to make a whole list entry invisible, when the property imgcnt is 0.
And I don´t know how to apply the converter by code (in OnNavigateTo) only to my ItemTemplate for pivotitem2.
Can anyone help?
UPDATE:
I did following with no success (all entries are not shown):
pivotitem1.DataContext = App.ViewSurroundingsData;
Binding mBinding = new Binding();
mBinding.Source = App.ViewSurroundingsData;
mBinding.Converter = new IntegerToVisibilityConverter();
lst2.SetBinding(LongListSelector.ItemsSourceProperty, mBinding);
And
public sealed class IntegerToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo language)
{
var item = (ViewModels.ViewModel_Surroundings)value;
if (item.imgcnt == 0)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo language)
{
return value is Visibility && (Visibility)value == Visibility.Visible;
}
Can't you just bind the imgcnt to the Visibility of the Button like this?
<Button Click="btn_ShowLocationDetails_Click" Tag="{Binding ID}" Style="{StaticResource mBlankButton}" Margin="1,0,-1,0"
Visibility="{Binding imgcnt, Converter={StaticResource IntegerToVisibilityConverter}}">
And then in your converter:
public object Convert(object value, Type targetType, object parameter, CultureInfo language)
{
return (int)value == 0 ? Visibility.Collapsed : Visibility.Visible;
}
Or am I missing something here? ;-)
I am writing an application in C#/WPF and am trying to figure out how to databind the width of the grids column definitions to a fraction of the screen width. Is this possible? Essentially I want something like this:
Grid = 2x2
Row 1 Height = 2/3 of screen height
Row 2 Height = 1/3 of screen height
Row 1 Width = 2/3 of screen width
Row 2 Width = 1/3 of screen width
I think that this correctly binds the full width to a column definition:
<ColumnDefinition Width="{Binding ElementName=Window1, Path=Width}"/>
but what I don't know how to do is perform an operation on the value it gets through the databinding... is this even possible? I feel like this is something I should be able to code into the XAML and not have to implement programmatically but I have little experience with UI design :( I would want something like:
<ColumnDefinition Width="{Binding ElementName=Window1, Path=Width} * 2 / 3"/>
but that is invalid
Should I just be writing a function to re-layout UI elements whenever the screen resizes? I feel like that is redundant... or is there some easy way of doing this that I don't know about? Any input welcome! Thanks!
It sounds like you just want to use star sizing:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
This will always give the first row 2/3 of the height and the second row 1/3 of the height, and the first column 2/3 of the width and the second column 1/3 of the width. It will be based on the size of the Grid, but if the Grid is the only child of the Window then that will be the same as the size of the Window.
I ran into a situation where I needed to bind the width of a control to a fraction of the height of another and I don't think there's a handy built-in way of dividing a bound property like that. I ended up making a converter that would divide a bound value by the converter parameter to solve this issue without resorting to code-behind and figured I'd share it in case it helps save someone else some time. I'm posting it here because this post was the first result when I was searching if there was a cleaner way.
Converter class:
[ValueConversion(typeof(double), typeof(double))]
public class DoubleDivisionConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value == null) { return 0.0; }
if(parameter == null) { return value; }
double param;
if(Double.TryParse(parameter.ToString(), out param))
{
if(param == 0) { return 0.0; }
return (double)value / param;
}
else
{
throw new ArgumentException("Could not parse converter parameter as double.");
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value == null) { return 0.0; }
if(parameter == null) { return value; }
double param;
if(Double.TryParse(parameter.ToString(), out param))
{
if(param == 0) { return 0.0; }
return (double)value * param;
}
else
{
throw new ArgumentException("Could not parse converter parameter as double.");
}
}
}
XAML: (Converter used on UniformGrid Width property)
<Window.Resources>
<converters:DoubleDivisionConverter x:Key="DoubleDivisionConverter"/>
</Window.Resources>
<Grid x:Name="sampleGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Grid.Resources>
<Border x:Name="rSample" Grid.Column="0" Grid.Row="0" Background="PaleVioletRed">
<TextBlock>
<TextBlock.Inlines>
<Run Text="{Binding ElementName=rSample, Path=ActualWidth, StringFormat={}{0:N1}px, Mode=OneWay}"/><Run Text=", "/><Run Text="{Binding ElementName=rSample, Path=ActualHeight, StringFormat={}{0:N1}px, Mode=OneWay}"/>
</TextBlock.Inlines>
</TextBlock>
</Border>
<!-- Set the UniformGrids width to 1/3 the height of the parent grid using the converter -->
<UniformGrid Grid.Column="1" Grid.Row="0" Columns="1"
Width="{Binding ElementName=sampleGrid, Path=ActualHeight, Converter={StaticResource DoubleDivisionConverter}, ConverterParameter=3, Mode=OneWay}">
<Border x:Name="gSample" Background="LightGreen">
<TextBlock>
<TextBlock.Inlines>
<Run Text="{Binding ElementName=gSample, Path=ActualWidth, StringFormat={}{0:N1}px, Mode=OneWay}"/><Run Text=", "/><Run Text="{Binding ElementName=gSample, Path=ActualHeight, StringFormat={}{0:N1}px, Mode=OneWay}"/>
</TextBlock.Inlines>
</TextBlock>
</Border>
<Border x:Name="ySample" Background="LightGoldenrodYellow">
<TextBlock>
<TextBlock.Inlines>
<Run Text="{Binding ElementName=ySample, Path=ActualWidth, StringFormat={}{0:N1}px, Mode=OneWay}"/><Run Text=", "/><Run Text="{Binding ElementName=ySample, Path=ActualHeight, StringFormat={}{0:N1}px, Mode=OneWay}"/>
</TextBlock.Inlines>
</TextBlock>
</Border>
<Border x:Name="bSample" Background="LightBlue">
<TextBlock>
<TextBlock.Inlines>
<Run Text="{Binding ElementName=bSample, Path=ActualWidth, StringFormat={}{0:N1}px, Mode=OneWay}"/><Run Text=", "/><Run Text="{Binding ElementName=bSample, Path=ActualHeight, StringFormat={}{0:N1}px, Mode=OneWay}"/>
</TextBlock.Inlines>
</TextBlock>
</Border>
</UniformGrid>
</Grid>
Result: