Horizontally stretch items with horizontal orientation - xaml

I'm looking to show a dynamic number of buttons in a horizontal way, so that they always fill up the space horizontally no matter how many items.
For example, when there are two button
__________________________________
| other controls |
| |
|________________________________|
| Button 1 | Button 2 | Button 3 |
----------------------------------
and button 2 gets hidden(collapsed), this should become
__________________________________
| other controls |
| |
|________________________________|
| Button 1 | Button 3 |
----------------------------------
Is this possible with Winrt/WP 8.1 xaml?

I would work with a Grid and set the column width to zero in order to hide it. Since all other columns have star values they should stretch accordingly. If everything fails you can recalculate the star values manually since you know the number of visible buttons.
Sample:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Foo" Margin="0,0,0,0" HorizontalAlignment="Stretch" />
<Button Grid.Column="1" Content="Foo" Margin="0,0,0,0" HorizontalAlignment="Stretch" />
<Button Grid.Column="2" Content="Foo" Margin="0,0,0,0" HorizontalAlignment="Stretch" />
</Grid>
Set the ColumnDefinition of one column to zero and the button is hidden and the other columns adjust accordingly.

You can always provide your own custom layout logic by deriving from Panel. Here's what I came up with:
StretchPanel.cs
class StretchPanel : Panel
{
#region Properties
public bool EqualWidths
{
get { return (bool)GetValue(EqualWidthsProperty); }
set { SetValue(EqualWidthsProperty, value); }
}
public static readonly DependencyProperty EqualWidthsProperty =
DependencyProperty.Register("EqualWidths", typeof(bool), typeof(StretchPanel), new PropertyMetadata(false, onEqualWidthsChanged));
#endregion
static void onEqualWidthsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var panel = (StretchPanel)d;
panel.InvalidateMeasure();
panel.InvalidateArrange();
}
protected override Size MeasureOverride(Size availableSize)
{
var renderedChildren = Children.Where(c => c.Visibility == Visibility.Visible);
var count = renderedChildren.Count();
Size childAvailableSize = availableSize;
if (EqualWidths)
childAvailableSize = new Size(availableSize.Width / count, availableSize.Height);
foreach (var child in renderedChildren)
child.Measure(childAvailableSize);
var totalHeight = renderedChildren.Max(c => c.DesiredSize.Height);
return new Size(availableSize.Width, totalHeight);
}
protected override Size ArrangeOverride(Size finalSize)
{
var renderedChildren = Children.Where(c => c.Visibility == Visibility.Visible);
var count = renderedChildren.Count();
var equalWidth = finalSize.Width / count;
var totalWidth = renderedChildren.Sum(c => c.DesiredSize.Width);
var totalHeight = renderedChildren.Max(c => c.DesiredSize.Height);
var x = 0.0;
foreach (var child in renderedChildren)
{
var r = new Rect();
r.X = x;
r.Y = 0;
r.Width = EqualWidths ? equalWidth : child.DesiredSize.Width / totalWidth * finalSize.Width;
r.Height = child.DesiredSize.Height;
child.Arrange(r);
x += r.Width;
}
return new Size(finalSize.Width, totalHeight);
}
}
You can use it like so:
<Page
x:Class="App19.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App19"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<Style TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="MinWidth" Value="0" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="16" />
<Setter Property="Foreground" Value="Yellow" />
<Setter Property="Margin" Value="0,10,0,0" />
</Style>
</Page.Resources>
<StackPanel>
<TextBlock>Different widths</TextBlock>
<local:StretchPanel EqualWidths="False">
<Button>a</Button>
<Button>big</Button>
<Button>purple</Button>
<Button>dishwasher</Button>
</local:StretchPanel>
<TextBlock>Equal widths</TextBlock>
<local:StretchPanel EqualWidths="True">
<Button>a</Button>
<Button>big</Button>
<Button>purple</Button>
<Button>dishwasher</Button>
</local:StretchPanel>
<TextBlock>Different widths, one child hidden</TextBlock>
<local:StretchPanel EqualWidths="False">
<Button>a</Button>
<Button>big</Button>
<Button Visibility="Collapsed">purple</Button>
<Button>dishwasher</Button>
</local:StretchPanel>
<TextBlock>Equal widths, one child hidden</TextBlock>
<local:StretchPanel EqualWidths="True">
<Button>a</Button>
<Button>big</Button>
<Button Visibility="Collapsed">purple</Button>
<Button>dishwasher</Button>
</local:StretchPanel>
</StackPanel>
</Page>
And a screenshot:

Related

How to change NavigationView Header when navigating to page?

The goal I'm trying to accomplish here is to change the NavigationView Header property when I press a NavigationView MenuItem, where it switches to a different page. I want the header to display the text on the button that was pressed but I'm very much learning to use the WinUI/XAML library still and looking at the gallery and documentation isn't really helping.
NavigationView.MenuItems on MainPage.xaml
<muxc:NavigationView.MenuItems>
<muxc:NavigationViewItem Icon="Home" Content="Home" x:Name="Menu1Item" Tag="Page1"/>
<muxc:NavigationViewItem Icon="Contact" Content="Account" x:Name="Menu2Item" Tag="Page2"/>
<muxc:NavigationViewItem Icon="Bullets" Content="Attendance" x:Name="Menu3Item" Tag="Page3"/>
<muxc:NavigationViewItem Icon="Library" Content="Grades" x:Name="Menu4Item" Tag="Page4"/>
<muxc:NavigationViewItem Icon="Flag" Content="Grad Reqs" x:Name="Menu5Item" Tag="Page5"/>
</muxc:NavigationView.MenuItems>
https://i.stack.imgur.com/ZeNdf.png
https://i.stack.imgur.com/t7eEj.png
EDIT:
MainPage.xaml:
<Page
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
x:Class="ProjectHurricanes.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ProjectHurricanes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
muxc:BackdropMaterial.ApplyToRootOrPageBackground="True"
>
<Page.Resources>
<!--This top margin is the height of the custom TitleBar-->
<Thickness x:Key="NavigationViewContentMargin">0,48,0,0</Thickness>
</Page.Resources>
<Grid>
<Border x:Name="AppTitleBar"
IsHitTestVisible="True"
VerticalAlignment="Top"
Background="Transparent"
Height="40"
Canvas.ZIndex="1"
Margin="48,8,0,0">
<StackPanel Orientation="Horizontal">
<Image x:Name="AppFontIcon"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Source="Assets/Square44x44Logo.png"
Width="16"
Height="16"/>
<TextBlock x:Name="AppTitle"
Text="Project"
VerticalAlignment="Center"
Margin="12, 0, 0, 0"
Style="{StaticResource CaptionTextBlockStyle}" />
</StackPanel>
</Border>
<muxc:NavigationView x:Name="NavigationViewControl"
IsTitleBarAutoPaddingEnabled="False"
IsBackButtonVisible="Visible"
Header="Home"
DisplayModeChanged="NavigationViewControl_DisplayModeChanged"
SelectionFollowsFocus="Enabled"
ItemInvoked="NavigationView_ItemInvoked"
PaneDisplayMode="Left"
Canvas.ZIndex="0">
<muxc:NavigationView.MenuItems>
<muxc:NavigationViewItem Icon="Home" Content="Home" x:Name="Menu1Item" Tag="Page1"/>
<muxc:NavigationViewItem Icon="Contact" Content="Account" x:Name="Menu2Item" Tag="Page2"/>
<muxc:NavigationViewItem Icon="Bullets" Content="Attendance" x:Name="Menu3Item" Tag="Page3"/>
<muxc:NavigationViewItem Icon="Library" Content="Grades" x:Name="Menu4Item" Tag="Page4"/>
<muxc:NavigationViewItem Icon="Flag" Content="Grad Reqs" x:Name="Menu5Item" Tag="Page5"/>
</muxc:NavigationView.MenuItems>
<Grid Padding="20">
<Frame x:Name="rootFrame"/>
</Grid>
</muxc:NavigationView>
</Grid>
</Page>
MainPage.xaml.cs:
OnItemInvoked:
private void NavigationView_OnItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
{
FrameNavigationOptions navOptions = new FrameNavigationOptions();
navOptions.TransitionInfoOverride = args.RecommendedNavigationTransitionInfo;
#pragma warning disable IDE0007 // Use implicit type
string navItemTag = args.InvokedItemContainer.Tag.ToString();
#pragma warning restore IDE0007 // Use implicit type
Type pageType = null;
if (navItemTag == "Page1")
{
pageType = typeof(Page1);
}
else if (navItemTag == "Page2")
{
pageType = typeof(Page2);
}
else if (navItemTag == "Page3")
{
pageType = typeof(Page3);
}
else if (navItemTag == "Page4")
{
pageType = typeof(Page4);
}
else if (navItemTag == "Page5")
{
pageType = typeof(Page5);
}
if (pageType == null)
{
return;
}
rootFrame.NavigateToType(pageType, null, navOptions);
}
You can add the ItemInvoked event to your NavigationView and in the event you can simple get the Content of the selected item.
An using-directive to muxc
using muxc = Microsoft.UI.Xaml.Controls;
The event in your MainPage.xaml.cs
private void NavigationView_ItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
{
if (NavigationView.SelectedItem is muxc.NavigationViewItem item)
{
sender.Header = item.Content.ToString();
}
}
The event added to your NavigationView
<muxc:NavigationView ItemInvoked="NavigationView_ItemInvoked" x:Name="NavigationView">

UWP: how to reflow controls based on grid width

I have two buttons placed horizontally. They are inside a grid. This grid containing two buttons has width 370. When the text on the button becomes large, it needs width more than 370. So what I want to do is, instead of placing then horizontally, I want to place them vertically dynamically when text will start cropping. Basically, I want auto-reflow behavior inside this grid for these two buttons based on width of the grid (not based on width of main window). So I want them to fit in 370 width and if they cannot, I want them to place themselves vertically. How can I achieve this?
I explored GridView but it will show buttons inside the box that comes with GridView so I do not want extra UI that comes with GridView unless we have an option to hide it?
I checked AdaptiveTrigger but that is based on width of window not of the control (grid in this case)
<Grid
Grid.Row="2"
Margin="0,36,0,28"
Width="370"
HorizontalAlignment="Left"
VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid
Grid.Column="0"
CornerRadius="3">
<Button
MinWidth="118"
MinHeight="30"
HorizontalAlignment="Left"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
AutomationProperties.Name="{x:Bind ViewModel.PrimaryActionAutomationName, Mode=OneWay}"
BorderThickness="1"
Click="{x:Bind ViewModel.InvokePrimaryAction}"
Content="{x:Bind ViewModel.PrimaryAction, Mode=OneWay}"
CornerRadius="3"
Style="{StaticResource AccentButtonStyle}" />
</Grid>
<Grid
Grid.Column="1"
CornerRadius="3"
Margin="32,0,0,0">
<HyperlinkButton
AutomationProperties.Name="{x:Bind ViewModel.SecondaryLinkAutomationName, Mode=OneWay}"
AutomationProperties.AutomationId="{Binding AutomationId, ConverterParameter=HyperlinkButton, Converter={StaticResource AutomationIdConverter}}"
Content="{x:Bind ViewModel.SecondaryText, Mode=OneWay}"
FontSize="14"
Margin="0,0,0,0"
Style="{StaticResource HyperlinkButtonStyle}"
NavigateUri="{x:Bind ViewModel.SecondaryLink, Mode=OneWay}" />
</Grid>
</Grid>
For your scenario, I'd suggest you custom a StateTrigger based on the StateTriggerBase Class to monitor the width of the Grid and apply visual states based on the width.
I've made a simple sample that you could refer to.
ControlSizeTrigger:
public class ControlSizeTrigger : StateTriggerBase
{
//private variables
private double _minHeight, _minWidth = -1;
private FrameworkElement _targetElement;
private double _currentHeight, _currentWidth;
//public properties to set from XAML
public double MinHeight
{
get
{
return _minHeight;
}
set
{
_minHeight = value;
}
}
public double MinWidth
{
get
{
return _minWidth;
}
set
{
_minWidth = value;
}
}
public FrameworkElement TargetElement
{
get
{
return _targetElement;
}
set
{
if (_targetElement != null)
{
_targetElement.SizeChanged -= _targetElement_SizeChanged;
}
_targetElement = value;
_targetElement.SizeChanged += _targetElement_SizeChanged;
}
}
//Handle event to get current values
private void _targetElement_SizeChanged(object sender, SizeChangedEventArgs e)
{
_currentHeight = e.NewSize.Height;
_currentWidth = e.NewSize.Width;
UpdateTrigger();
}
//Logic to evaluate and apply trigger value
private void UpdateTrigger()
{
//if target is set and either minHeight or minWidth is set, proceed
if (_targetElement != null && (_minWidth > 0 || _minHeight > 0))
{
//if both minHeight and minWidth are set, then both conditions must be satisfied
if (_minHeight > 0 && _minWidth > 0)
{
SetActive((_currentHeight >= _minHeight) && (_currentWidth >= _minWidth));
}
//if only one of them is set, then only that condition needs to be satisfied
else if (_minHeight > 0)
{
SetActive(_currentHeight >= _minHeight);
}
else
{
SetActive(_currentWidth >= _minWidth);
bool bbb = _currentWidth >= _minWidth;
Debug.WriteLine("Widthtrigger :" + bbb);
}
}
else
{
SetActive(false);
}
}
}
MainPage.xaml:
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ControlSizeStates">
<VisualState x:Name="SizeChange">
<VisualState.StateTriggers>
<local:ControlSizeTrigger MinWidth="800" TargetElement="{x:Bind Path=MyStackPanel}" />
<!--<AdaptiveTrigger MinWindowHeight="500" />-->
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyStackPanel.Background" Value="Red" />
<Setter Target="MyStackPanel.Orientation" Value="Horizontal" />
<Setter Target="MyButton.Foreground" Value="Black" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="MyStackPanel" Width="100" Height="200" Background="AliceBlue" Orientation="Vertical">
<Button x:Name="MyButton" Foreground="Red" Content="Click" Click="Button_Click"/>
<Button x:Name="MyButton2" Foreground="Red" Content="Click" />
</StackPanel>
</Grid>
MainPage.cs:
public MainPage()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MyStackPanel.Width = 1100;
}

MVVM binding cutom property to view model

I am new in MVVVM so please forgive me if it is stupid question. I am using this example http://www.codeproject.com/Articles/36848/WPF-Image-Pixel-Color-Picker-Element and included there library to get color of indicated by user pixel of image. it looks nice and dipsalys in rectangle selected color but i neeed to bind the selecteed value to viewmodel.
here is my xaml code:
<Window x:Class="MovieEditor.View.PixelSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:ColorPickerControls;assembly=ColorPickerControls"
xmlns:local="clr-namespace:MovieEditor.MVVMCommon"
Title="FilterDesigner" Height="550" Width="550"
Icon="..\Resources\Images\icon.ico"
xmlns:VM="clr-namespace:MovieEditor.ViewModel">
<Window.DataContext>
<VM:PixelSelectorVM/>
</Window.DataContext>
<Window.Resources>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter"/>
</Window.Resources>
<Grid Background="#FF191919" >
<DockPanel>
<Grid Margin="10,10,10,1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto" MinHeight="38"/>
</Grid.RowDefinitions>
<Border BorderBrush="White" BorderThickness="5" Margin="0,39,0,11">
<ctrls:ImageColorPicker Binding.XmlNamespaceManager="{Binding p PixelSelectorVM.MyImageColorPicker, UpdateSourceTrigger=PropertyChanged}"
x:Name="image" Source ="{Binding Frame}" Margin="0,36,0,0"
/>
</Border>
<Border Width="77"
HorizontalAlignment="Center"
BorderBrush="White" BorderThickness="1" Margin="263,2,182,435">
<Rectangle Fill="{Binding ElementName=image, Path=SelectedColor,
Converter={StaticResource ColorToBrushConverter}}" RenderTransformOrigin="0.549,0.429" Margin="1"/>
</Border>
<Button Content="Save" Command="{Binding Save}" Margin="165,0,0,4" Grid.Row="1" HorizontalAlignment="Left" Width="60"/>
<Label Content="Selected pixel color:" HorizontalAlignment="Left" Height="18" Margin="140,11,0,0" VerticalAlignment="Top" Width="110"/>
<Button Content="Cancel" Command="{Binding Cancel}" Margin="0,1,165,4" HorizontalAlignment="Right" Width="60" RenderTransformOrigin="0.5,0.5" Grid.Row="1">
</Button>
</Grid>
</DockPanel>
</Grid>
</Window>
</code>
And here is my view model:
public class PixelSelectorVM : ViewModelBase
{
private BitmapImage frame;
public MainWindowVM parentMainWindowVM;
private ImageColorPicker imageColorPicker;
public ImageColorPicker MyImageColorPicker
{
get
{
return this.imageColorPicker;
}
set
{
this.imageColorPicker = value;
OnPropertyChanged("MyImageColorPicker");
}
}
public BitmapImage Frame
{
get
{
return this.frame;
}
set
{
this.frame = value;
OnPropertyChanged("Frame");
}
}
public PixelSelectorVM(BitmapImage image, MainWindowVM mainWindowVM)
{
this.frame = image;
this.parentMainWindowVM = mainWindowVM;
this.imageColorPicker = new ImageColorPicker();
this.imageColorPicker.Source = image;
}
public PixelSelectorVM() { }
public ICommand Save
{
get
{
return new RelayCommand(SaveExecute);
}
}
public ICommand Cancel
{
get
{
return new RelayCommand(CancelExecute);
}
}
private void SaveExecute()
{
}
private void CancelExecute()
{
}
}
Please suggest me solution how can i pass the selected color to view model
You should be able to bind ImageColorPicker's SelectedColor to ViewModel's Property.
So in XAML add the binding:
SelectedColor="{Binding MySelectedColor, Mode=TwoWay}"
And in VM add the MySelectedColor property:
private Color selectedColor;
public Color MySelectedColor
{
get
{
return this.selectedColor;
}
set
{
this.selectedColor = value;
OnPropertyChanged("MySelectedColor");
}
}
When control's SelectedColor changes, it should automatically update the MySelectedColor in your VM.

TextBox not triggering PropertyChanged event

I am struggling to figure out why a propertychanged event or lostfocus event is not being triggered when I enter text into a textbox and navigate away from the control.
I am building a Universal Windows Platform app.
I know I'm doing something retarded but I just don't see it.
Any suggestions?
XAML:
<Page
x:Class="xxx.Client.FormPage"
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:viewModels="using:xxx.xxx.ViewModels"
Background="LightBlue"
mc:Ignorable="d">
<Page.Resources>
<Style x:Key="TextBoxStyle" TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextAlignment" Value="Center" />
</Style>
</Page.Resources>
<Page.DataContext>
<viewModels:FormViewModel />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding InstructorNameInput}" Style="{StaticResource TextBoxStyle}"
PlaceholderText="Instructor Name" />
<TextBox Grid.Row="1" Text="{Binding InstructorIdInput}" Style="{StaticResource TextBoxStyle}"
PlaceholderText="Instructor Id" />
<TextBox Grid.Row="2" Text="{Binding CourseInput}" Style="{StaticResource TextBoxStyle}"
PlaceholderText="Course" />
<Button Grid.Row="4" Content="Accept" Command="{Binding Submit}"
HorizontalAlignment="Stretch"
Foreground="Black" />
</Grid>
</Page>
ViewModel:
public partial class FormViewModel : ViewModelBase
{
public FormViewModel()
{
InstructorName = new RequiredField("Instructor's Name:");
InstructorId = new RequiredField("Instructor's Employee#:");
Course = new RequiredField("Course:");
var courses = CourseFactory.Produce();
var administration = new Administration(courses, null);
Submit = new DelegateCommand(_=> OnSubmit(), CanSubmit);
}
string _instructorNameInput = null;
public string InstructorNameInput
{
get { return _instructorNameInput; }
set
{
if (_instructorNameInput != value)
{
_instructorNameInput = value;
OnNotifyPropertyChanged();
}
}
}
string instructorIdInput = null;
public string InstructorIdInput
{
get { return instructorIdInput; }
set
{
if (instructorIdInput != value)
{
instructorIdInput = value;
OnNotifyPropertyChanged();
}
}
}
string courseInput = null;
public string CourseInput
{
get { return courseInput; }
set
{
if (courseInput != value)
{
courseInput = value;
OnNotifyPropertyChanged();
}
}
}
public RequiredField InstructorName { get; }
public RequiredField InstructorId { get; }
public RequiredField Course { get; }
public ObservableCollection<RequiredField> RequiredFields { get; } = new ObservableCollection<RequiredField>();
}
ViewModel.internal:
public partial class FormViewModel
{
static void OnSubmit()
{
var adminsistration = new Administration();
}
bool CanSubmit(object obj) => !GetUnsatisfied().Any();
IEnumerable<RequiredField> GetUnsatisfied()
{
if (string.IsNullOrEmpty(InstructorIdInput))
{
RequiredFields.Add(InstructorId);
}
else
{
var result = 0;
var isNumeric = int.TryParse(InstructorIdInput, out result);
if (!isNumeric)
{
RequiredFields.Add(new RequiredField(InstructorId.About, "Instructor ID must be numeric"));
}
}
if (string.IsNullOrEmpty(InstructorNameInput))
{
RequiredFields.Add(InstructorName);
}
if (string.IsNullOrEmpty(CourseInput))
{
RequiredFields.Add(Course);
}
return RequiredFields;
}
}
The default binding mode for UWP as MSDN says:
The default is OneWay.
Set it to TwoWay:
<TextBox Grid.Row="0" Text="{Binding InstructorNameInput, Mode=TwoWay}" .../>

Silverlight DataGridRow Background color change based on a column value and bind from the datagrid itemsource

I am trying to color the row based on a column value and may be other calculations in the value converter, but as long as I set the background value to any binding or anything but the hardcoded color Value="Red" in the setter, it throws a XAML parsing error. I am implementing like this:
<sdk:DataGrid ItemsSource="{Binding
EmailJobs}"
AutoGenerateColumns="False"
Height="Auto"
HorizontalAlignment="Center"
Name="dgEmailJObs"
VerticalAlignment="Top"
Width="Auto" Grid.Row="2">
<sdk:DataGrid.RowStyle>
<Style TargetType="sdk:DataGridRow">
<Style.Setters>
<Setter Property="Background"
Value="{Binding Path=Status,
Converter={StaticResource
valueConverter}}"/>
</Style.Setters>
</Style>
</sdk:DataGrid.RowStyle>
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Customer"
Width="Auto" Binding="{Binding
Customer}" />
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Program"
Width="Auto" Binding="{Binding
Program}" />
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True"
Header="Application" Width="Auto"
Binding="{Binding Application}"/>
<sdk:DataGridTextColumn
CanUserReorder="True"
CanUserResize="False"
CanUserSort="True" Header="Status"
Width="Auto" Binding="{Binding
Status}"></sdk:DataGridTextColumn>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Last
Created By" Width="Auto"
Binding="{Binding LastChangedBy}"/>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Last
Created On" Width="Auto"
Binding="{Binding
LastChangedOn,StringFormat='MM/DD/YYYY
hh:mm tt'}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
I am using MVVM and dont wanna use the triggering event. All I want is to simply supply the fourth column value to the converter, but it blows up, should be pretty simple jsut lack of XAML binding knowledge :( any help
I think I see... Silverlight 4 doesn't allow (anymore) bindings into Setters.
However there are 2 simple solutions to solve your issue :
You can remove the <sdk:DataGrid.RowStyle> and its content and replace it by RowStyle="{Binding Path=Status, Converter={StaticResource valueConverter}}" as a property of your datagrid (example below)
<sdk:DataGrid Grid.Column="1" ItemsSource="{Binding EmailJobs}" RowStyle="{Binding Path=Status, Converter={StaticResource valueConverter}}" AutoGenerateColumns="False" HorizontalAlignment="Center" Name="dgEmailJObs" Width="Auto" Margin="0,0,0,87" LoadingRow="dgEmailJObs_LoadingRow">
Or, you can manage it in the code behind after triggering the event LoadingRow:
void dgEmailJObs_LoadingRow(object sender, DataGridRowEventArgs e)
{
myClass c = e.Row.DataContext as myClass;
if (c != null)
{
if (c.Status == "Stopped")
{
e.Row.Background = new SolidColorBrush(Colors.Red);
}
else
{
e.Row.Background = new SolidColorBrush(Colors.Green);
}
}
}
Hope that helps ;)
private void grdPendingRequest_LoadingRow(object sender, DataGridRowEventArgs e)
{
string changedColPath = string.Empty;
dynamic itemData = (dynamic)e.Row.DataContext;
if (itemData != null)
changedColPath = itemData.Changed_Field;
if (changedColPath != string.Empty)
{
string colPath;
System.Windows.Data.Binding binding;
string[] ChangedColNameList = null;
foreach (DataGridColumn col in grdPendingRequest.Columns)
{
if (col is DataGridBoundColumn)
{
binding = (col as DataGridBoundColumn).Binding;
colPath = binding.Path.Path;
ChangedColNameList = changedColPath.Split(';');
if (ChangedColNameList.Contains(colPath))
{
FrameworkElement felt = col.GetCellContent(e.Row);
FrameworkElement felt_result = GetParent(felt, typeof(DataGridCell));
if (felt_result != null)
{
DataGridCell cell = (DataGridCell)felt_result;
//cell.Background = new SolidColorBrush(Color.FromArgb(255, 196, 219, 249));
cell.Background = new SolidColorBrush(Colors.Red);
}
}
}
}
}
}
my value converter:
public class EmailJobStatusConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value.ToString()=="Stopped") ?
new SolidColorBrush(Colors.Red) :
new SolidColorBrush(Colors.Green);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
SolidColorBrush resultColor = value as SolidColorBrush;
if (resultColor.Color == Colors.Green)
{
return "Green";
}
else
return "Red";
}
}