How do I change the background color of a textblock in MVVM-WPF - textblock

I am new to WPF technology. i am using MVVM architecture.
I want to change the background of textblock based on viewmodel's attribute.
e.g If i am using 'brush' object, I want to bind it to background color of textblock.
<TextBlock Margin="0,1"
HorizontalAlignment="Center"
FontFamily="Arial"
FontSize="16"
Text="{Binding Line}"
TextWrapping="Wrap"
Background="{Binding brushobj}"/>
How to implement it?

You could define it like this, inside your ViewModel.
private Brush _brushobj;
/// <summary>
/// Gets or sets the BrushObject.
/// </summary>
public Brush BrushObj
{
get
{
return _brushobj;
}
set
{
// Set value
_brushobj = value;
// Notify UI that the value has changed.
RaisePropertyChanged("BrushObj");
// OnPropertyChanged("BrushObj"); // Use the appropriate function to notify the UI.
}
}
Then simply set the value with something like this:
BrushObj = (Brush)new BrushConverter().ConvertFromString("Green");
Last you bind it to your View like you did in your question:
Background="{Binding BrushObj}"
Edit: I tried to make a project myself just to verify that this was indeed working and the following code worked fine. If it's still not working it's more likely to be something with your MVVM setup causing problem.
MainWindowViewModel:
namespace WpfApplication1
{
public class MainWindowViewModel : ObservableObject
{
private Brush _brushobj = (Brush)new BrushConverter().ConvertFromString("Red");
public Brush BrushObj
{
get
{
return _brushobj;
}
set
{
_brushobj = value; // Set value
RaisePropertyChanged("BrushObj"); // Notify UI that the value has changed.
}
}
}
}
MainWindow:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Margin="0,1"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontFamily="Arial"
FontSize="16"
Text="Testing a lot of stuff here! important stuff!"
TextWrapping="Wrap"
Background="{Binding BrushObj}"/>
</Grid>
</Window>

Related

MvvmCross ViewModel class with Init() method crashes at design time

I try to implement design time data into my code (see DataContext below).
The problem is, I have an exception "Object reference not set to an instance of an object" in visual studio with MainView.xaml opened in design view. I tried to debug it with another VS instance but got no breakpoints.
I narrowed it down. As soon as there is an Init() method on the ViewModel something fails. This Init() is being called by the MvvmCross framework.
If I remove the Init() method it works very well in Designer. So, I suspect MvvmCross is missing a "IsInDesignMode" check, but since I'm new to MvvmCross it may be very likely my fault.
Full sample is here:
https://github.com/indazoo/MvvmCross_DesignData
This sample throws the exception. You can remove the Init() method in MainViewModel.cs and the code runs fine in Designer.
To debug the designer I disabled "Just my code" and enabled all CLR exceptions in the attaching VS instance but got no breakpoints. Any tips welcome.
Here some code excerpt (more in the sample code on github):
The page is derived from LayoutAwarePage (MvvmCross TipCalc Sample).
<localViews:LayoutAwarePage
x:Class="App2.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:localViews="using:App2.Views"
xmlns:cirrViews="using:Cirrious.MvvmCross.WindowsCommon.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="{Binding Source={StaticResource DesignFactory}, Converter={StaticResource DesignConverter}, ConverterParameter=MainViewModel}"
>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBlock Text="1234"></TextBlock>
<TextBlock Text="123123"></TextBlock>
<TextBlock Text="{Binding DesignTimeHello, Mode=OneWay, FallbackValue=DesgnRuntimeFallback}" FontSize="30" />
<TextBlock Text="123123"></TextBlock>
<TextBox Text="{Binding MyProperty, Mode=TwoWay, FallbackValue=FallBackTextBox}" />
</StackPanel>
</Grid>
Code behind of XAML:
public sealed partial class MainView : LayoutAwarePage
{
public MainView()
{
this.InitializeComponent();
}
public new MainViewModel ViewModel
{
get { return (MainViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
}
MainViewModel:
public class MainViewModel : MvxViewModel
{
private IDataService Data { get; set; }
public MainViewModel(IDataService data)
{
Data = data;
}
public string DesignTimeHello
{
get { return Data != null ? Data.TestData : "Missing"; }
}
//!!! If you comment this method everything works !!!
public void Init()
{
int i = 0;
i++;
}
.....
App.Xaml
<Application
x:Class="App2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CoreHelpers="using:App2.Helpers"
xmlns:local="using:App2">
<Application.Resources>
<ResourceDictionary >
<CoreHelpers:DesignTimeHelper x:Key="DesignTime" />
<local:DesignFactory x:Key="DesignFactory"/>
<local:DesignTimeConverter x:Key="DesignConverter" />
</ResourceDictionary>
</Application.Resources>

Conditional Hiding of WinRT/XAML Controls Using Style - Possible?

In my WinRT/Phone 8.1 app I have a form with a number of Grids (serving as wrappers) each containing two or more TextBlocks. I want to show only data that is available, meaning that if the content TextBlock of a particular Grid is empty I want to hide the entire Grid.
For instance:ยด
<Grid x:Name="NameSection">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
x:Name="NameLabel"
Text="Name:" />
<TextBlock Grid.Row="1"
x:Name="Name"
Text="{Binding Name}" />
</Grid>
If the Name TextBlock is empty, the entire Grid's visibility should be collapsed.
Adding logic for this either to code behind or (worse) the ViewModel could get messy for this long form, so I wonder if I can achieve this using XAML and styles. How can it be done in WinRT? Can I style the Grid such that it's visibility is based on the content in one of its subviews?
Converter
public class NullToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value == null ? Visibility.Collapsed: Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
then use it like this
<Grid x:Name="NameSection" Visibility={Binding Name, Converter={StaticResource MyNullConverter}}>
edit:
you can add string.IsNullOrEmpty(value as string) insted of value == null, if you want to check empty strings as well

Get ItemsControl children to inherit foreground in WinRT

In a custom TemplatedControl I have an ItemsControl that is populated outside of the custom TemplatedControl. I want the (future) children of the ItemsControl to automatically inherit the Foreground value from the ItemsControl.
I want to be able to change the Foreground value from the TemplatedControl, and have the child controls update their Foreground as well.
Here's the ItemsControl I have:
<ItemsControl x:Name="PrimaryItems" ItemsSource="{TemplateBinding PrimaryItems}" Foreground="{TemplateBinding MyCustomForeground}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And when I use the TemplatedControl, it'll look like this:
<Grid>
<Controls:MyCustomControl MyCustomForeground="Blue">
<Controls:MyCustomControl.PrimaryItems>
<Button Content="Test button"/>
</Controls:MyCustomControl.PrimaryItems>
</Controls:MyCustomControl>
</Grid>
I want the Button foreground to automatically be Blue, since that's what I set as MyCustomForeground in my TemplatedControl.
Any tips?
Have you tried {TemplateBinding xxxx} ?
<Controls:MyCustomControl MyCustomForeground="{TemplateBinding Foreground}">
<Controls:MyCustomControl.PrimaryItems>
<Button Content="Test button"/>
</Controls:MyCustomControl.PrimaryItems>
</Controls:MyCustomControl>
I see, this one is tricky. If you try to use DependencyProperty heritage, this won't work (using the foreground property of your UserControl) :
<UserControl
x:Class="TestApp1.CustomControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400" Foreground="Blue">
<StackPanel x:Name="PART_Container">
<Button Content="Test"/>
<TextBlock Text="Test"/>
</StackPanel>
</UserControl>
If you try this snippet, the phone's template for the button will override Foreground="Blue" and thus it will have a white (or black depending on the theme) foreground. Note that Textblock is not styled, and won't display this behavior, it will successfully inherit the blue foreground from its parent UserControl.
How to walkaround this ? You seem to declare a custom dependency property MyCustomForeground, so you can implement a logic in the DependencyPropertyChanged handler. But you also have to apply your custom foreground each time your PrimaryItems changes.
Here's a working sample :
public sealed partial class CustomControl : UserControl
{
public CustomControl()
{
this.InitializeComponent();
}
public Brush MyCustomForeground
{
get { return (Brush)GetValue(MyCustomForegroundProperty); }
set { SetValue(MyCustomForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for MyCustomForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCustomForegroundProperty =
DependencyProperty.Register("MyCustomForeground", typeof(Brush), typeof(CustomControl), new PropertyMetadata(null, OnCustomForegroundChanged));
private static void OnCustomForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CustomControl ctrl = (CustomControl)d;
ctrl.ApplyCustomForeground();
}
public UIElement PrimaryItems
{
get { return (UIElement)GetValue(PrimaryItemsProperty); }
set { SetValue(PrimaryItemsProperty, value); }
}
// Using a DependencyProperty as the backing store for PrimaryItems. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PrimaryItemsProperty =
DependencyProperty.Register("PrimaryItems", typeof(UIElement), typeof(CustomControl), new PropertyMetadata(null, OnPrimaryItemsChanged));
private static void OnPrimaryItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CustomControl ctrl = (CustomControl)d;
// PART_Container is where I store my PrimaryItems
ctrl.PART_Container.Children.Clear();
ctrl.PART_Container.Children.Add((UIElement)e.NewValue);
ctrl.ApplyCustomForeground();
}
private void ApplyCustomForeground()
{
// PART_Container is where I store my PrimaryItems
foreach (var child in PART_Container.Children)
{
// Foreground is inherited by Control or TextBlock, or other classes...
// You would be better off using reflection here but that's off topic
if (child is Control)
{
((Control)child).Foreground = MyCustomForeground;
}
else if (child is TextBlock)
{
((TextBlock)child).Foreground = MyCustomForeground;
}
}
}
}

FindAncestor implementation in WP8 ListBox

I want to implement a Listbox binding directly and here is the code i used in WPF syntax
<ListBox Name="lboxData" ItemsSource="{Binding}">
<ListBox.ItemTemplate >
<DataTemplate>
<StackPanel>
<ToggleButton x:Name="toggleChild" Style="{StaticResource ChapterHeadingStyle}"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" // This is what i have to change . I want to set it based on the status of the ListBoxItem & Given code is the one i used in WPF app
/>
<ListBox Visibility="{Binding IsChecked, ElementName=toggleChild, Converter={StaticResource boolToVis}}" ItemsSource="{Binding pages}" Margin="10,0,0,0" >
<ListBox.ItemTemplate >
<DataTemplate>
//here is displaying child items one by one ..
</DataTemplate>
</ListBox.ItemTemplate >
</ListBox>
</ListBox.ItemTemplate >
</DataTemplate>
</StackPanel>
</ListBox>
The problem is that in WP8 RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem} is not supported . So how can i achieve the same thing in WP8. I want to set the toggle button as Checked if the container ListboxItem is selected , else i want to set the IsChecked as False.
I'll start by writing a comparer class
public class ElementComparer : FrameworkElement
{
public object Element1
{
get { return (object)GetValue(Element1Property); }
set { SetValue(Element1Property, value); }
}
// Using a DependencyProperty as the backing store for Element1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty Element1Property =
DependencyProperty.Register("Element1", typeof(object), typeof(ElementComparer), new PropertyMetadata(null, UpdateResult));
public object Element2
{
get { return (object)GetValue(Element2Property); }
set { SetValue(Element2Property, value); }
}
// Using a DependencyProperty as the backing store for Element2. This enables animation, styling, binding, etc...
public static readonly DependencyProperty Element2Property =
DependencyProperty.Register("Element2", typeof(object), typeof(ElementComparer), new PropertyMetadata(null, UpdateResult));
public bool Result
{
get { return (bool)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
// Using a DependencyProperty as the backing store for Result. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ResultProperty =
DependencyProperty.Register("Result", typeof(bool), typeof(ElementComparer), new PropertyMetadata(false, OnResultChanged)); //added changed handler
private static void OnResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ElementComparer ec = d as ElementComparer;
//if true then set the element 2 to element 1 of the comparer otherwise null
ec.Element2 = ((bool)e.NewValue) ? ec.Element1 : null;
}
private static void UpdateResult(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ElementComparer ec = d as ElementComparer;
ec.Result = object.ReferenceEquals(ec.Element1, ec.Element2);
}
}
then I'll bind IsChecked from togglebutton to the Result of ElementComparer and will bind the Element1 and Element2 of the comaprer with the current item and the SelectedItem of lboxData (ListBox)
<ListBox Name="lboxData" ItemsSource="{Binding}">
<ListBox.ItemTemplate >
<DataTemplate>
<StackPanel>
<!--added Mode=TwoWay to binding of Element2-->
<local:ElementComparer x:Name="ElementComparer"
Element1="{Binding}"
Element2="{Binding SelectedItem, ElementName=bookTOCBox, Mode=TwoWay}" />
<!--removed Mode=OneWay from binding of IsChecked and added Mode=TwoWay-->
<ToggleButton x:Name="toggleChild" Content="{Binding name}"
Style="{StaticResource ChapterHeadingStyle}"
IsChecked="{Binding Result, ElementName=ElementComparer, Mode=TwoWay}"/>
...
</StackPanel>
the trick is to compare the selected item of the list to the current item to detect if it is selected as long as the name of parent listbox is "lboxData", this will work in WP8 too
Update summary
Removed one way binding from IsChecked property of toggle to Result of ElementComparer
Added two way binding to SelectedItem to Element2 of ElementComparer
added property changed handler for the Result property in ElementComparer
when the result is changes and is true (toggle is checked) push the value of Element1 to Element2
since the Element2 is bound to SelectedItem it force other items's result to false hence turn off the toggle and collapse the child list
added Mode=TwoWay to IsChecked property of toggle as seems quit unpredictable without it
Extras
additionally if you don't want to see ugly looking blue selection in list items then you may add the following to your resources too
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="Transparent">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

how to change color of ellipses in wp8 in xaml.cs

i m trying to create a windows phone 8 app.in this app i have 4 ellipses on a page and i want them to change color depending on a certain integer's value every 15 seconds. i have got the timer part down but i m stuck on how to make them change colors. i would really appreciate some help.
i have googled it alot but could not find a clear solution. i m new at apps so please tell me each and every step
here is where i create them in xaml:
<Ellipse x:Name="l1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="42,339,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" Grid.ColumnSpan="2"/>
<Ellipse x:Name="l2" Grid.Column="1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="111,339,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
<Ellipse x:Name="l3" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="42,471,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" Grid.ColumnSpan="2"/>
<Ellipse x:Name="l4" Grid.Column="1" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="111,471,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
try implementing this;
yourEllipsesName.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 255(R), 255(G), 255(B)));
with this you can pass your color code in RGB format. Hope this helps.
The solution #Vyas_27 provided is the easiest (+1) and in most cases sufficient.
As you are starting, you may want to learn something about DataBinding. In this case your code may look like this:
In XAML:
<Ellipse x:Name="l1" Fill="{Binding FirstBrush}" HorizontalAlignment="Left" Height="100" Margin="42,339,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" Grid.ColumnSpan="2"/>
// other similar
In code behind xaml.cs:
public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseProperty(string propName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName)); }
private Color firstColor = Color.FromArgb(0xFF, 0xF4, 0xF4, 0xF5);
public Color FirstColor
{
get { return firstColor; }
set { firstColor = value; RaiseProperty("FirstBrush"); }
}
public SolidColorBrush FirstBrush { get { return new SolidColorBrush(firstColor); } }
public MainPage()
{
InitializeComponent();
this.DataContext = this; // set the DataContext so binding can work
}
// Then you change the color like this, and the color of your ellipse is updated
FirstColor = Color.FromArgb(255, 120, 120, 0);
}
You will surely find many blogs, tutorials and so on, so I won't post everything here. Just couple of remarks - what is imortant to make it work:
in XAML as you can see, define Binding to Property (the name is very important)
your Page needs to implement INotifyPropertyChanged - event, and you should provide method which will fire the event
set the DataContext of your Page
properties to which you bind must be public Properties with suitable getter (for OneWay binding)
One remark to my solution and #Vyas_27 - this will work if your Timer runs on UI (then it's probably DispatcherTimer). If you have timer running on other Thread, then the Color change you must invoke via Dispatcher.