Dynamically change style of element with C# - c#

I have a chart with 4x LineSeries. I defined two different styles for representing the lines, and I want to be able to change the style applied to a particular LineSeries dynamically (based, for example, on the user tapping a button, etc).
I cannot seem to work out how to update the style from c#. Any help appreciated!
I have tried:
lineChartMood.PolylineStyle = this.Resources.PolylineStyle2 as Style;
but this returns a Null exception.
Here is the XAML for the page, including the style definitions:
<phone:PhoneApplicationPage
x:Class="Bhutaan.ChartingTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:local="clr-namespace:Bhutaan"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<Style x:Key="PolylineStyle" TargetType="Polyline">
<Setter Property="StrokeThickness" Value="5"/>
</Style>
<Style x:Key="PolylineStyle2" TargetType="Polyline">
<Setter Property="StrokeThickness" Value="1"/>
</Style>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="TEST" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="added" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,-0,12,0">
<ScrollViewer>
<StackPanel>
<TextBlock Text="Great! That's been saved." FontSize="30" Margin="0,0,0,0"/>
<!-- Chart -->
<charting:Chart
x:Name="myChart"
Margin="0,20,0,0"
Height="350"
Style="{StaticResource PhoneChartStyle}"
Template="{StaticResource PhoneChartPortraitTemplate}">
<!-- Series -->
<charting:LineSeries
x:Name="lineChartMood"
Title="Mood"
ItemsSource="{Binding}"
DependentValuePath="MoodValue"
IndependentValuePath="Timestamp"
PolylineStyle="{StaticResource PolylineStyle}" >
<charting:LineSeries.LegendItemStyle>
<Style TargetType="charting:LegendItem">
<Setter Property="Margin" Value="5 0 5 0"/>
</Style>
</charting:LineSeries.LegendItemStyle>
</charting:LineSeries>
<!-- Series -->
<charting:LineSeries
Title="Energy"
ItemsSource="{Binding}"
DependentValuePath="EnergyValue"
IndependentValuePath="Timestamp">
<charting:LineSeries.LegendItemStyle>
<Style TargetType="charting:LegendItem">
<Setter Property="Margin" Value="5 0 5 0"/>
</Style>
</charting:LineSeries.LegendItemStyle>
</charting:LineSeries>
<!-- Series -->
<charting:LineSeries
Title="Mental"
ItemsSource="{Binding}"
DependentValuePath="MentalValue"
IndependentValuePath="Timestamp">
<charting:LineSeries.LegendItemStyle>
<Style TargetType="charting:LegendItem">
<Setter Property="Margin" Value="5 0 5 0"/>
</Style>
</charting:LineSeries.LegendItemStyle>
</charting:LineSeries>
<!-- Series -->
<charting:LineSeries
Title="Hunger"
ItemsSource="{Binding}"
DependentValuePath="HungerValue"
IndependentValuePath="Timestamp">
<charting:LineSeries.LegendItemStyle>
<Style TargetType="charting:LegendItem">
<Setter Property="Margin" Value="5 0 5 0"/>
</Style>
</charting:LineSeries.LegendItemStyle>
</charting:LineSeries>
</charting:Chart>
</StackPanel>
</ScrollViewer>
</Grid>
</Grid>
</phone:PhoneApplicationPage>

I tested your code and found the cause of the problem.
You get the NullReferenceException because the field this.lineChartMood isn't set by the application for some unknown reason.
You have to obtain this line series object by yourself. There are two possible ways to get it:
var lineSeriesWay1 = this.FindName("lineChartMood");
var lineSeriesWay2 = myChart.Series.OfType<LineSeries>().First(ls => ls.Name == "lineChartMood");
But I would recommend to set the field this.lineSeriesMood explicitly in the constructor, like this:
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// because the code 'this.FindName("lineChartMood")' doesn't work in the constructor, I'll use the following line:
this.lineChartMood = this.myChart.Series.OfType<LineSeries>().First(ls => ls.Name == "lineChartMood");
// other code
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.lineChartMood.PolylineStyle = (Style)this.Resources["PolylineStyle2"];
this.lineChartMood.Refresh(); // you should call this method so that the style is applied
}
}
Then you will be able to reference to your series without exceptions.

Why not add your resources in the App.xaml and refer them using App.Current.Resources?? I say this because I feel the program might not be able to refer the local resource defined on the specific page. I might be wrong. This is not a solution just a workaround.

lineChartMood.PolylineStyle = this.Resources.PolylineStyle2 as Style;
should be
lineChartMood.PolylineStyle = this.Resources["PolylineStyle2"] as Style;??

Related

Parse Exception occurring due to my Styling

I am creating a WPF application in C# using XAML. I have looked into the documentation of creating Styles for XAML.
It looks to be working correctly in the Designer before I actually run my application. Upon running my application I receive a parse exception. Looking at the line and position indicated, <Style="{StaticResource T}" /> is the cause of this error. Removing it solves the issue, but this requires me to do an inline Style which I would like to avoid.
The XAML code for the Page encountering this issue is below and I would appreciate any feedback and guidance on this issue. The Style not working here is the x:Key="T" TargetType="Border".
<Page x:Class="NGClient1.Screen1.BE2.WindowBe2Tablet"
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:NGClient1.Screen1.BE2"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="WindowBe2Tablet" Width="1024" Height="1280" Background="Black">
<Grid>
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Source="Resources/backdrop.png" Stretch="UniformToFill" Grid.ColumnSpan="2" Grid.RowSpan="3" />
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="Advert Section Here" />
</StackPanel>
<Border Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" BorderBrush="White" BorderThickness="4" Background="Black" Margin="40, 40, 40, 40" Opacity="0.5"/> -->
<Border Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Style="{StaticResource T}" /> <!-- Exception being thrown here, unsure why -->
<StackPanel Grid.Column="0" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="Lower Section Left Here" />
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="Lower Section Right Here" />
</StackPanel>
</Grid>
</Grid>
<Page.Resources>
<Style x:Key="T" TargetType="Border" > <!-- x:Key causing exception, unsure why -->
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="BorderThickness" Value="4"/>
<Setter Property="Background" Value="Black"/>
<Setter Property="Margin" Value="40, 40, 40, 40"/>
<Setter Property="Opacity" Value="0.5"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="25"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</Page.Resources>
</Page>
When using StaticResources, the order of defining and referencing a resource in XAML matters.
Provides a value for any XAML property attribute by looking up a reference to an already defined resource. Lookup behavior for that resource is analogous to load-time lookup, which will look for resources that were previously loaded from the markup of the current XAML page as well as other application sources, and will generate that resource value as the property value in the run-time objects.
As stated in the documentation for static resource lookup:
Forward references cannot be resolved by a static resource reference.
In your case, the resource section is at the bottom of the page, so the resource will be defined after it is first referenced through StaticResource. In order to solve the issue, you have to either move the resources section to a position before resources defined within it are referenced or use DynamicResource instead.
<Border Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Style="{DynamicResource T}"/>
The DynamicResource Markup Extension instead processes a key by creating an expression, and that expression remains unevaluated until the app runs, at which time the expression is evaluated to provide a value.

How to format chat conversations in markdowntextblock in Windows Universal application (windows 10)

I am building a chat application in which i have below xaml code -
<Page
x:Class="MyProject1.MainPage"
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:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" Background="Black">
<Grid Background="White" Name="mainGrid">
<Border BorderBrush="Cyan" BorderThickness="0.2" Margin="3,0,3,3">
<ListView x:Name="ListView" VerticalAlignment="Bottom" SelectionMode="None" IsItemClickEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<controls:MarkdownTextBlock Name="markdownBlock" Text="{Binding Text}" TextWrapping="Wrap" FontFamily="Segoe-UI">
</controls:MarkdownTextBlock>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="Black" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Border>
</Grid>
</Page>
I use below code in my code behind to send text to the MarkdownTextBlock control
messages.Add(new Message() { Text = "**Person 1:** " + message });
and the response -
messages.Add(new Message() { Text = "**Person 2:** " + activity.Text });
Right now the format is plain background like below -
Person 1: Hello, How are you doing?
Person 2: Hi, I am doing great!
How can i format these plain messages to get conversation feel like we have in skype as
I am new to Windows Application development, I am not sure how to format the text as conversations within markdown text block, could you guide me?
Do I need to create a table within markdown control and pass the messages by having background color on rows? not sure how to do this. Any help?
Updated view -
<Page
x:Class="MyProject1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="using:XamlAnimatedGif"
xmlns:local="using:LISA_Speech1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" Background="Black">
<Page.Resources>
<Style x:Key="MessageItemStyle" TargetType="SelectorItem">
<Setter Property="Height" Value="Auto" />
<Setter Property="Width" Value="450" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="5" />
</Style>
<Style
x:Key="RightAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style
x:Key="LeftAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="Orange" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<styleSelectors:MessageContainerStyleSelector
x:Key="MessageContainerStyleSelector"
ReceivedStyle="{StaticResource LeftAlignedMessageStyle}"
Sender="{x:Bind CurrentUser, Mode=OneWay}"
SentStyle="{StaticResource RightAlignedMessageStyle}" />
<DataTemplate x:Key="MessageTemplate" x:DataType="messages:Message">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Message, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<StackPanel
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind SentDate, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="MessageItemPanelTemplate">
<ItemsStackPanel VerticalAlignment="Bottom" ItemsUpdatingScrollMode="KeepLastItemInView" />
</ItemsPanelTemplate>
</Page.Resources>
<Grid Background="Black" Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Border BorderBrush="Cyan" BorderThickness="0.2" Margin="3,0,3,3">
<ListView
x:Name="Messages"
Margin="10"
CanDrag="False"
CanReorderItems="False"
IsItemClickEnabled="False"
IsTapEnabled="False"
ItemContainerStyleSelector="{StaticResource MessageContainerStyleSelector}"
ItemTemplate="{StaticResource MessageTemplate}"
ItemsPanel="{StaticResource MessageItemPanelTemplate}"
ItemsSource="{x:Bind Text, Mode=OneWay}" />
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="35"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox x:Name="text" KeyUp="TextBox_KeyDown" Grid.Column="0" PlaceholderText="Type something or say 'Start Listening'" FontSize="17" BorderBrush="Purple" Margin="0,10,0,-7" Height="58" VerticalAlignment="Top">
</TextBox>
<Button x:Name="button" Click="Button_Click" Grid.Column="1" Height="58" Width="35" Padding="0" Background="Purple" Margin="0,10,0,-7">
<SymbolIcon x:Name="symbol" Symbol="Microphone" Width="35" HorizontalAlignment="Center" Foreground="White" Margin="-2,-8,-2,-2"/>
</Button>
</Grid>
<MediaElement x:Name="Media"></MediaElement>
</Grid>
</Page>
You can achieve this quite simple using an ItemContainerStyleSelector. What this will do is allow you to create some logic that takes your chat message object and determine if it was sent or received.
For example, your model may look like this:
public class Message
{
public Guid Id { get; set; }
public string UserTo { get; set; }
public string UserFrom { get; set; }
public string Message { get; set; }
public DateTime SentDate { get; set; }
}
You then will create the StyleSelector like this:
public class MessageContainerStyleSelector : StyleSelector
{
public Style SentStyle { get; set; }
public Style ReceivedStyle { get; set; }
public string Sender { get; set; }
protected override Style SelectStyleCore(object item, DependencyObject container)
{
var message = item as Message;
if (message != null)
{
return message.UserFrom.Equals(this.Sender, StringComparison.CurrentCultureIgnoreCase)
? this.SentStyle
: this.ReceivedStyle;
}
return base.SelectStyleCore(item, container);
}
}
From here, we then need to create the styles that will be used with this style selector and they are very simple. They will also give you flexibility for the colors you're looking to use for the sent or received messages.
In your view, you may have styles set up like this:
<Page.Resources>
<Style x:Key="MessageItemStyle" TargetType="SelectorItem">
<Setter Property="Height" Value="Auto" />
<Setter Property="Width" Value="450" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="5" />
</Style>
<Style
x:Key="RightAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style
x:Key="LeftAlignedMessageStyle"
BasedOn="{StaticResource MessageItemStyle}"
TargetType="SelectorItem">
<Setter Property="Background" Value="Orange" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<styleSelectors:MessageContainerStyleSelector
x:Key="MessageContainerStyleSelector"
ReceivedStyle="{StaticResource LeftAlignedMessageStyle}"
Sender="{x:Bind CurrentUser, Mode=OneWay}"
SentStyle="{StaticResource RightAlignedMessageStyle}" />
<DataTemplate x:Key="MessageTemplate" x:DataType="messages:Message">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Message, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<StackPanel
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind SentDate, Mode=OneWay}" />
</StackPanel>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="MessageItemPanelTemplate">
<ItemsStackPanel VerticalAlignment="Bottom" ItemsUpdatingScrollMode="KeepLastItemInView" />
</ItemsPanelTemplate>
</Page.Resources>
In these styles, you see that we are using a base style which the two chat message styles inherit from. We are using a right/left alignment in this scenario so your messages will show on either side of the screen but here you can customize each style to your own needs.
A few other things to point out here, we are also declaring the DataTemplate that will be used to show layout the message. Notice here we aren't doing anything custom. Every message will layout the same, it's the container style that will alter how they appear in the ListView.
Also the ItemsPanelTemplate at the bottom allows the ListView to present the messages bottom up in a chat style format.
In regards to how this all ties together with your ListView in the page, you would now use the MessageContainerStyleSelector like this:
<ListView
x:Name="Messages"
Margin="10"
CanDrag="False"
CanReorderItems="False"
IsItemClickEnabled="False"
IsTapEnabled="False"
ItemContainerStyleSelector="{StaticResource MessageContainerStyleSelector}"
ItemTemplate="{StaticResource MessageTemplate}"
ItemsPanel="{StaticResource MessageItemPanelTemplate}"
ItemsSource="{x:Bind Messages, Mode=OneWay}" />
When you're running the app, you'll get something that looks similar to this:
Hopefully this is something to go off and you can take this further with this detail. Feel free to ask any questions, I'm happy to help.
The first thing I would do is a custom control called MessageViewer. In this one you could have a parameter that tells you what's the direction of the message, or just two another classes MessageViewerIn and MessageViewerOut that could be like this:
XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Fill="LightBlue" RadiusX="15" RadiusY="15"></Rectangle>
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10" Text="Some dummy text here"></TextBlock>
</Grid>
Now, via code you could understand if you need an image on the LEFT or RIGHT column of this grid. Everything will depend if the text you're showing is from an user or if YOU are sending this text.
So, you could add some methods to check it (or directly do in in the constructor of this class like:
MessageViewer(String message, bool orientation)
MessageViewer msgVwr = new MessageViewer("Your Text", true/false)
...and if its true your icon will be on the left, and when it's false on the right. Inside of the control you can access various element, so for example, if you'll give a name for a grid
<Grid Name="grdMain">
you can acces his properties via code, like grdMain.Background, and set it and change it.
For the space on the left/right you could use margins of the interlat textbox, setted on "10, 10, 30, 10" for right-space (yours) messages and "30, 10, 10, 10" for left-space (incoming) messages.
For doing some text work, like bold or other, check out elements you can put inside a grid: everything you want :)
All this elements you could put in a simple ListView to show them like a chat.

(C#) DataBinding layout programmatically

I have this xaml with grid of accounts:
<UserControl x:Class="SpectroCoin.Controls.AccountInfo"
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"
mc:Ignorable="d"
xmlns:effects="clr-namespace:SpectroCoin.Effects"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="130" d:DesignWidth="480">
<UserControl.Resources>
<Style x:Key="MainInfoStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="32"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
<Style x:Key="ReservedInfoStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="20"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Margin="0,0,0,0" >
<StackPanel Orientation="Vertical" Grid.Column="0" Margin="0,0,0,0">
<TextBlock FontSize="24" Text="Label" x:Name="txtLabel" Margin="0"/>
<TextBlock FontSize="50" Text="{Binding Account.AvailableStr}" Margin="50,-10,0,0" Foreground="#FFF9AF28"/>
<TextBlock FontSize="24" Margin="50,-15,0,0" Visibility="{Binding ReservedVisibility}">
<Run Foreground="Gainsboro" Text="{Binding LocalizedResources.reserved, Source={StaticResource LocalizedStrings}, StringFormat='\{0\} '}"/>
<Run Foreground="Gainsboro" Text="{Binding Account.ReservedStr}"/>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
And I am adding this layout programatically for every account I have using foreach:
foreach (Account.Account account in GetModel().BalancePageModel.Accounts)
{
var myAccountInfoControl = new AccountInfo(account);
//myAccountInfoControl.txtLabel.SetBinding()
AccountsInfo.Children.Add(myAccountInfoControl);
}
My layout is created, but the values of AvailableStr, txtLabel and ReservedStr doesn't change because I haven't enabled Databinding programatically, how do I do that?
You have to set the DataContext of myAccountInfoControl to the account object.
myAccountInfoControl.DataContext = account;
If you do this the bindings that you have done in the XAML should be changed by removing the "Account." part like this:
Hope this help.

Binding to DataGrid of TabItem not Working using MVVM

I have a small application to help myself learn WPF and MVVM etc. I have been using the example by Josh Smith found here to construct my own application. I have got the application adding TabItems, but the embedded DataGrid which is bound to an ObservableCollection<ResourceViewModel> is not showing any data, see the image below:
The DataGrid is the section surrounded in blue. The UserControl also seems to be showing the in the tab itself for some reason, but that is not the problem I am asking about here. The UserControl contains a DataGrid which is bound as follows
<DataGrid ItemsSource="{Binding Resources}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox,
Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro"
AlternationCount="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...</DataGrid>
The Resources property is defined in the ViewModels namespace as
internal class ResourceDataViewModel : WorkspaceViewModel
{
readonly ResourceDataRepository resourceRepository;
public ObservableCollection<ResourceViewModel> Resources { get; private set; }
...
}
Where the ResourceViewmodel holds the information for each row of the DataGrid. I can confirm that the Resource property is populated. When I use the same model outside of MVVM and populate Resource in the same way it works. Can someone provide me with and idea of why this could be happening?
I have attempted to set the explicit path for the binding
ItemsSource="{Binding Path=(viewModels:Resources)}"
but this also does not work. Thanks for your time.
Edit. To address comments. I set the DataContext in the App.xaml.cs file by
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
// Create the ViewModel to which
// the main window binds.
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
// When the ViewModel asks to be closed,
// close the window.
EventHandler handler = null;
handler = delegate
{
mainWindowViewModel.RequestClose -= handler;
window.Close();
};
mainWindowViewModel.RequestClose += handler;
// Allow all controls in the window to
// bind to the ViewModel by setting the
// DataContext, which propagates down
// the element tree.
window.DataContext = mainWindowViewModel;
window.Show();
}
The XAML of the MainWindow:
<Window x:Class="ResourceStudio.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
Title="MainWindow" Height="629.4" Width="814.4">
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="284*"/>
<ColumnDefinition Width="567*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<DockPanel KeyboardNavigation.TabNavigation="None"
Background="#FFBEC8D8"
Grid.ColumnSpan="2"
Margin="0,0,0.4,0">
<Menu DockPanel.Dock="Top"
Background="#FFF9F9F9"
BorderBrush="Black"
KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="_File">
<MenuItem Header="Load _Resource..."
Height="Auto"
Command="{Binding LoadResourceCommand}"/>
<MenuItem Header="_Add Language..."
Height="Auto"/>
<Separator/>
<MenuItem Header="Close _Workspace"
Height="Auto"
Command="{Binding CloseCommand}"/>
<MenuItem Header="E_xit"
Height="Auto" Command="{Binding CloseCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" MaxHeight="24" Background="#FFF9F9F9">
<ToolBar Background="#FFF9F9F9">
<Button ToolBar.OverflowMode="Never">One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ToolBar>
</ToolBarTray>
</DockPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,0.4,23.6" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding Path=Workspaces}"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TabStripPlacement="Top"
Height="Auto"
Width="Auto">
</TabControl>
</Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" Margin="0,0.4,0.4,-0.4">
<StatusBarItem DockPanel.Dock="Left" Background="#FF007ACC" Margin="0,2,0,0">
<TextBlock Text="Ready" Margin="5,0,0,0"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Where the MainWindowResources.xaml is:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
The full code for the ResourceControl.xaml is:
<UserControl x:Class="ResourceStudio.Views.ResourceControl"
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:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="control">
<DockPanel DataContext="{Binding ElementName=control}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBox Text="M" DockPanel.Dock="Top" Name="searchBox" />
<Grid DockPanel.Dock="Top">
<Border BorderBrush="#FF007ACC" BorderThickness="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid ItemsSource="{Binding Path=(viewModels:Resources)}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro" AlternationCount="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid.Resources>
<dataAccess:SearchValueConverter x:Key="searchValueConverter"/>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="dataAccess:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource searchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(dataAccess:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF007ACC"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Border>
</Grid>
</DockPanel>
</UserControl>
The TextBox is bound to the DataGrid. When the user types into that TextBox the DataGrid filters and highlights the cells which contains the required text. This however, is not the problem and this code works, it is just the binding to the DataGrid I am interested in. Thanks again for tour time.
Edit2: According to #dkozl's comments I have removed the DataContext="{Binding ElementName=control}" from the DockPanel declaration, so we now have
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...
and in the MainWindowResource.xaml I now have
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl DataContext="{Binding}"/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
This has not worked. That is my DataGrid in the ResourceControl is not being populated. Thanks again for your time it is most appreciated...
Your UserControl DockPanel.DataContext is bound to ResourceControl control and not to ResourceDataViewModel class. What you need to do instead is to bind DataContext of ResourceControl in your DataTemplate. To achive that first remove DataContext="{Binding ElementName=control}" from ResourceControl.DockPanel and then bind ResourceControl.DataContext to your object by <views:ResourceControl DataContext={Binding}"/>. Also you need to change DataGrid items binding from ItemsSource="{Binding Path=(viewModels:Resources)}" to ItemsSource="{Binding Path=Resources}".
Not part of the original question but same template applies to tab header and tab content because DataTemplate is type specific and in this case tab header content and tab content is the same thing. To solve the issue remove DataTemplate for viewModels:ResourceDataViewModel type and put this directly into your main TabControl:
<TabControl.ContentTemplate>
<DataTemplate>
<views:ResourceControl DataContext={Binding}"/>
</DataTemplat‌​e>
</TabControl.ContentTemplate>

WPF - how to determine why this XAML style code is not working?

Any advice how to fault find to work out why the Grid.Resources styles in this XAML is not making any difference it seems to the end result?
Note I'm using Charting from the WPFToolkit so to adjust how a chart looks it seems one has to apply the style areas (suggested by someone on the forum).
So my question is generically, noting I'm trying to adjust the look of a 3rd party graph, how can I debug/fault-find to understand what's going wrong? Is there a debugging trick? For example when I increased the BorderThickness to 30 I couldn't see a difference. What I'm really after is the equivalent of FireBug for HTML/CSS, which lets you understand/view what CSS is being applied to what elements.
EDIT: So I really (I think) want to be able to walk the object tree of the graph, and referring back to the template changes put in the Grid.Resources area, see why they didn't occur.
<Window
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:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" mc:Ignorable="d" x:Name="Splash" x:Class="MyInternetUsage.SplashWindow"
Title="SplashWindow" Height="421" Width="570">
<DockPanel>
<StackPanel VerticalAlignment="Top" DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Configure" HorizontalAlignment="Left" Margin="0" Width="78" VerticalAlignment="Center" Name="ConfigureButton" Click="ConfigureButton_Click" />
<Button Content="Start" Name="StartButton" Width="78" Click="StartButton_Click" />
<Button Content="Stop" Name="StopButton" Width="78" Click="StopButton_Click" />
</StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="Summary" Grid.Column="0"/>
<GridSplitter HorizontalAlignment="Right"
VerticalAlignment="Stretch" Grid.Column="1" ResizeBehavior="PreviousAndNext"
Width="5" Background="#FFBCBCBC"/>
<Grid Grid.Column="2">
<Grid.Resources>
<Style x:Key="GooglePolylineStyle" TargetType="Polyline">
<Setter Property="StrokeThickness" Value="30"/>
</Style>
<Style x:Key="GoogleLineDataPointStyle" TargetType="chartingToolkit:LineDataPoint">
<Setter Property="Background" Value="#0077CC" />
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="BorderThickness" Value="30"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="chartingToolkit:LineDataPoint">
<Grid x:Name="Root" Opacity="1">
<ToolTipService.ToolTip>
<StackPanel Margin="2,2,2,2">
<ContentControl Content="{TemplateBinding IndependentValue}"
ContentStringFormat="{}{0:MMMM d, yyyy}"/>
<ContentControl Content="{TemplateBinding DependentValue}"
ContentStringFormat="Visits {0:###,###,###}"/>
</StackPanel>
</ToolTipService.ToolTip>
<Ellipse StrokeThickness="{TemplateBinding BorderThickness}"
Stroke="{TemplateBinding BorderBrush}"
Fill="{TemplateBinding Background}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Real Time Graph" VerticalAlignment="Top" Grid.Row="0" />
<chartingToolkit:Chart Grid.Row="1"
Name="RTGraph"
BorderThickness="0" >
</chartingToolkit:Chart>
</Grid>
</Grid>
</DockPanel>
</Window>
As SeeSharp says, Snoop allows you to view the object tree at runtime (and change values and see results etc). However, I think your problem here might be that you're not explicitly applying the style on the <chartingToolkit:Chart /> object.
Try one of the following to see if it makes a difference:
Apply style on object:
<chartingToolkit:Chart
...
Style="{DynamicResource GoogleLineDataPointStyle}"
...
>
Or remove the key from the style so that it only has a TargetType attribute (should make it the default style for all objects of that type:
<Style TargetType="chartingToolkit:LineDataPoint">
...
</Style>
Since you've given the styles an x:Key. you need to explicitly set the style property of your items to use that style as a resource.
Have you tried removing the x:Key properties from your style, and moving your style declaration from the grid and into the chart?
See output window in VS. All binding errors logged in this window. Also, tool Snoop alow to see bindings with errors.
If this is a WPF application, i would like to suggest one silly thing. Excuse me for that. Please copy and paste the same code into a silverlight application and then inspect the element using Firebug.
Also, in your code snippet, i think you need to give :
TargetType="{x:Type Polyline}"
TargetType="{x:Type chartingToolkit:LineDataPoint}"
If you want these styles to be applied on the target type automatically, then remove the x:Key.
Also, you can find a list of useful WPF utilities # http://www.simple-talk.com/dotnet/.net-tools/essential-tools-for-the-wpf-novice/

Categories

Resources