I have used Telerik RadGrid to build a grid. The grid itself works but it is databound to a SQL database. I am trying to display rows with different colors.
Here is an example of what I am trying to do:
Here is what I have so far:
protected void SummaryGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item is GridDataItem)
{
GridItem dataItem = e.Item;
if (dataItem["Red"].Text = "Red")
{
dataItem.BackColor = Color.Red;
}
}
}
Any help with this would be great.
Try the following code to change the color based on a particular value.
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item is GridDataItem)
{
GridDataItem dataItem = e.Item;
if (dataItem["Size"].Text == "1")
{
dataItem.BackColor = Drawing.Color.Red;
}
}
You can use style triggers to accomplish this.
App.xaml
<Style BasedOn="{StaticResource GridViewRowStyle}" TargetType="telerik:GridViewRow">
<Style.Triggers>
<DataTrigger Binding="{Binding YourObject.Size Converter={StaticResource ColorConverter}}" Value="Red">
<Setter Property="Background" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
<DataTrigger Binding="{Binding YourObject.Size Converter={StaticResource ColorConverter}}" Value="Green">
<Setter Property="Background" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
ColorConverter.cs
public class ColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int)
{
if ((int)value > 100)
return "Red";
else
return "Green";
}
else
return "Default";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// TODO: Implement this method
throw new NotImplementedException();
}
}
Figured it out and its really simple actually, just going to say if the text equals what you need it to be then its a red row or if its something else then its whatever other color. Really easy but a lot of people have had this issue so hopefully this helps others.
if (e.Item is GridDataItem)
{
var item = (GridDataItem)e.Item;
if (item["Type"].Text == "RedRow")
{
item.BackColor = Color.Red;
}
else if(item["Type"].Text == "OrangeRow")
{
item.BackColor = Color.Orange;
}
}
Related
How would I properly bound to ItemsSource column via Dependency property of control (Datagrid), in order to set It's DataTrigger working?
My goal that works without dependency property:
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding NAME}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
And this is how I want It to work:
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding HideRow, ElementName =_myGrid}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
My dependency property :
public static DependencyProperty HideRowProperty =
DependencyProperty.Register("HideRow", typeof(PersonsModel), typeof(My_DataGrid),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
///<summary>Property for hiding rows, based on column name</summary>
public PersonsModel HideRow
{
get { return (PersonsModel)GetValue(HideRowProperty); }
set { SetValue(HideRowProperty, value); }
}
And this is how I try to bind control in XAML:
<ctl:My_DataGrid ItemsSource="{Binding Persons}" HideRow="{Binding Persons.NAME}">
More explanation: ItemsSource Persons is ObservableCollection of PersonsModel (which is type of Dependency property).
I'm getting BindingExpression path error: 'NAME' property not found on 'object' ''ObservableCollection`1' error.
Based on your comments, your goal is to tell DataGrid to hide the row that has some property value == null. Hence, you have to assign the property's name to HideRow property and use a converter which uses reflection to get the property value and affect the style trigger.
You have 2 options, the first one is simpler and you don't need the HideRow property at all:
Change RowStyle a bit, Here you will pass the name of the property as a ConverterParameter (so it might be Name, Age, etc...)
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding ., Converter={StaticResource NullPropertyToBoolConverter}, ConverterParameter=Name}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Where NullPropertyToBoolConverter is
public class NullPropertyToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is PersonsModel person && parameter is string propertyName)
{
return typeof(PersonsModel).GetProperty(propertyName)?.GetValue(person, null) == null;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The converter is defined in resources of one of DataGrid's parents (or in Application.xaml)
<converters:NullPropertyToBoolConverter x:Key="NullPropertyToBoolConverter" />
It is getting the value of Name, and return true if it was null, and this will cause the row visibility to be Collapsed.
This option is suitable because in both options you have to define RowStyle but here you don't need to define a dependency property.
Here you would change HideRow type to string instead of PersonsModel, and use it like this:
<ctl:My_DataGrid ItemsSource="{Binding Persons}" HideRow="Name" >
So, it might be Name, Age, etc...
You'd define <DataGrid.RowStyle> similar to this
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource NullPropertyToBoolConverter2}">
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=Self}" />
<Binding Path="HideRow" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGrid}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
and define the Converter to return Collapse if property's value is null, otherwise Visible.
public class NullPropertyToBoolConverter2 : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is Obj obj && values[1] is string str)
{
return typeof(Obj).GetProperty(str)?.GetValue(obj, null) == null ? Visibility.Collapsed : Visibility.Visible;
}
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have a splitview,that contains StackPanels,I want to define a style which modify the color when hover in each of those StackPanels,is this possible?
this is my code:
<StackPanel Orientation="Horizontal" Style="{Binding Source={StaticResource HyperlinkPointerOverForegroundThemeBrush}}" >
<Button x:Name="MenuButton1"
Width="50" Height="50" Background="Transparent">
<Button.Content>
<Image Source="images/chercher.png"></Image>
</Button.Content>
</Button>
<TextBlock Text="Resultats" FontSize="18" VerticalAlignment="Center" Foreground="#727271"/>
</StackPanel>
and I have defined the styles like that:
<SolidColorBrush x:Key="HyperlinkButtonBackgroundThemeBrush" Color="#e6e6e6" />
<SolidColorBrush x:Key="HyperlinkButtonBorderThemeBrush" Color="#e6e6e6" />
<SolidColorBrush x:Key="HyperlinkDisabledThemeBrush" Color="#e6e6e6" />
<SolidColorBrush x:Key="HyperlinkForegroundThemeBrush" Color="#e6e6e6" />
<SolidColorBrush x:Key="HyperlinkPointerOverForegroundThemeBrush" Color="#e6e6e6" />
<SolidColorBrush x:Key="HyperlinkPressedForegroundThemeBrush" Color="#e6e6e6" />
but when I hover,none of the StackPanels Foreground have changed
thanks for help
I don't think you can do that only with style. But, if you really want to use a style, you can combine with a behavior.
The behavior can use PointerEntered and PointerExited events to set a new Background. Next, the behavior can be setted in your style.
In order to implements this type of solution, you have to add the Behaviors SDK extensions (go to add references > Universal Windows > Extensions).
The definition of the behavior (for example) :
public class HoverBehavior : DependencyObject, Microsoft.Xaml.Interactivity.IBehavior
{
private Panel _associatedObject;
private Brush _baseBrush;
public Brush HoverBrush
{
get { return (Brush)GetValue(HoverBrushProperty); }
set { SetValue(HoverBrushProperty, value); }
}
public static readonly DependencyProperty HoverBrushProperty =
DependencyProperty.Register("HoverBrush", typeof(Brush), typeof(HoverBehavior), new PropertyMetadata(null));
public Brush DefaultBrush
{
get { return (Brush)GetValue(DefaultBrushProperty); }
set { SetValue(DefaultBrushProperty, value); }
}
public static readonly DependencyProperty DefaultBrushProperty =
DependencyProperty.Register("DefaultBrush", typeof(Brush), typeof(HoverBehavior), new PropertyMetadata(null));
public DependencyObject AssociatedObject
{
get { return _associatedObject; }
}
public void Attach(DependencyObject associatedObject)
{
_associatedObject = associatedObject as Panel;
if (_associatedObject != null)
{
_baseBrush = _associatedObject.Background;
if (_associatedObject != null)
{
_associatedObject.PointerEntered += _associatedObject_PointerEntered;
_associatedObject.PointerExited += _associatedObject_PointerExited;
}
}
}
private void _associatedObject_PointerExited(object sender, PointerRoutedEventArgs e)
{
if (_associatedObject != null)
_associatedObject.Background = HoverBrush;
}
private void _associatedObject_PointerEntered(object sender, PointerRoutedEventArgs e)
{
if (_associatedObject != null)
_associatedObject.Background = DefaultBrush ?? _baseBrush;
}
public void Detach()
{
_associatedObject.PointerEntered -= _associatedObject_PointerEntered;
_associatedObject.PointerExited -= _associatedObject_PointerExited;
}
}
In the xaml, you have to add a "using" for the Interactivity namespace :
<Page xmlns:i="using:Microsoft.Xaml.Interactivity" />
And, you can define a new style (named SpStyle for example) :
<Style TargetType="StackPanel"
x:Key="SpStyle">
<Setter Property="i:Interaction.Behaviors">
<Setter.Value>
<i:BehaviorCollection>
<local:HoverBehavior DefaultBrush="Yellow"
HoverBrush="Green" />
</i:BehaviorCollection>
</Setter.Value>
</Setter>
</Style>
The HoverBrush property of the behavior is the color of the StackPanel when the mouse pointer is hover the StackPanel, and DefaultBrush (can be unset) is the color of the StackPanel when the mouse pointer is not hover the StackPanel.
I have one combo box in which I have some items like:
Item1
Item2
Item3
Corresponding every item there is image like item1 has image img1.jpg, item2 has image img2.jpg and item3 has image img3.jpg. When we select item from combox it will show their corresponding image in label.
I got answer of my question and here it's:
<xmlns:local="clr-namespace:ImageMVVM_Learning"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:EnumToImageConverter x:Key="conv"/>
</Window.Resources>
<Grid>
<StackPanel>
<ComboBox x:Name="combo" ItemsSource="{Binding MyProperty}"/>
<Image Source="{Binding ElementName=combo,Path=SelectedValue,Converter={StaticResource conv}}"/>
</StackPanel>
</Grid>
</Window>
Do this in your viewmodel class:
public enum MyEnum
{
A,
B,
C
}
public class EnumToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
switch ((MyEnum)value)
{
case MyEnum.A:
return new BitmapImage(new Uri(#"Images\A.png", UriKind.Relative));
case MyEnum.B:
return new BitmapImage(new Uri(#"Images\B.png", UriKind.Relative));
}
}
return new BitmapImage(new Uri(#"Images\A.png", UriKind.Relative));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Can anyone give out the best practices for playing around with controls at runtime such as creating a new view,adding views inside a view,adding controls to containers using MVVM pattern without breaking mvvm pattern??
I am using MVVMlight toolkit..
please help me out in this regard..
Thanks in advance......
This post discusses the strategies for creating views (dialogs) from your view models.
Edit:
From your comment I take it that you got an user interface that has an add and delete button. The add button should add an item (type ?) to a ItemsControl ... hope that's correct.
So, how would I do this, well I would create a view model that has an ObservableCollecion<ItemViewModel>. The ItemViewModle is the view mode that represents the item that should be added to the ItemsControl (so in your case the view model backing your "rangeView").
Then I would add two commands that handle the addition and deletion of items. Both commands just add/remove ItemViewModels from your collection.
To show the items in the view I would bind the ItemControl.ItemsSource property to the collection in your main view model (i.e. the one holding the ItemViewModel instances). The I would supply an ItemTemplate to render the items on the screen.
Ok, here is an example of what I think you are trying to do (at least conceptionally). Complete Source Code here. In the example I used a ListBox as it allows me easily to determine which item is selected, this depends on your szenario. Also note that you have complete freedom to customize the Template, the ItemPanelTemplate, and DataTemplate to fit your needs. You can even use this approacht to create PanoramaPages in WP7!
2nd edit: ItemsControl does not have a SelectedItem property. To get to it you have to use a control inheriting from Selector (e.g. a ListBox as I did) or you can use the Selector directly.
ItemViewModel:
public class ItemViewModel : ViewModelBase
{
#region [Name]
public const string NamePropertyName = "Name";
private string _name = null;
public string Name {
get {
return _name;
}
set {
if (_name == value) {
return;
}
var oldValue = _name;
_name = value;
RaisePropertyChanged(NamePropertyName);
}
}
#endregion
}
MainViewModel:
public class MainViewModel : ViewModelBase
{
public MainViewModel() {
if (IsInDesignMode) {
this.Items = new ObservableCollection<ItemViewModel>(Enumerable.Range(0, 10).Select((x, i) => new ItemViewModel() { Name = "Design Time Item " + i }));
} else {
// Code runs "for real"
}
}
#region [AddCommand]
private RelayCommand _addCommand;
public RelayCommand AddCommand {
get {
return _addCommand ?? (_addCommand = new RelayCommand(
() => {
this.Items.Add(new ItemViewModel() { Name = "New item - " + DateTime.Now });
}
));
}
}
#endregion
#region [DeleteCommand]
private RelayCommand _deleteCommand;
public RelayCommand DeleteCommand {
get {
return _deleteCommand ?? (_deleteCommand = new RelayCommand(
() => {
this.Items.Remove(this.SelectedItem);
},
() => { return this.SelectedItem != null; }
));
}
}
#endregion
#region [Items]
public const string ItemsPropertyName = "Items";
private ObservableCollection<ItemViewModel> _items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
set {
if (_items == value) {
return;
}
var oldValue = _items;
_items = value;
RaisePropertyChanged(ItemsPropertyName);
}
}
#endregion
#region [SelectedItem]
public const string SelectedItemPropertyName = "SelectedItem";
private ItemViewModel _selectedItem = null;
public ItemViewModel SelectedItem {
get {
return _selectedItem;
}
set {
if (_selectedItem == value) {
return;
}
var oldValue = _selectedItem;
_selectedItem = value;
RaisePropertyChanged(SelectedItemPropertyName);
// important in SL to notify command that can execute has changed !
this.DeleteCommand.RaiseCanExecuteChanged();
}
}
#endregion
}
MainPage.xaml
<UserControl
x:Class="MvvmLight1.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"
mc:Ignorable="d"
Height="300"
Width="300"
DataContext="{Binding Main, Source={StaticResource Locator}}"
>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- we are dealing with ItemViewModels now -->
<Border BorderThickness="0,0,0,1" BorderBrush="Gray" Padding="10,5">
<TextBlock Text="{Binding Name}"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Margin="5,10" Content="Add" Command="{Binding AddCommand}" Width="70"/>
<Button Margin="5,10" Content="Delete" Command="{Binding DeleteCommand}" Width="70"/>
</StackPanel>
</Grid>
</UserControl>
I am totally lost and I would really appreciate your help on this.
My final goal is to create a user control that will contain two control templates. Square and a Circle. Based on a type the control will display one or the other. When the mouse enters the shape the Opacity will change to 0.2.
The first part works but the Opacity does not change. The event is triggered and a GoToState is called, but with no result. The Opacity stays 1.
My XAML:
<UserControl.Resources>
<ControlTemplate x:Key="TemplateSquare" TargetType="{x:Type local:KeyControl}">
<Canvas x:Name="MainCanvas" VerticalAlignment="Center" HorizontalAlignment="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CenterRectangle" Storyboard.TargetProperty="(UIElement.Opacity)" Duration="0" To=".2"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="CenterRectangle" Fill="Red" Width="100" Height="100"></Rectangle>
</Canvas>
</ControlTemplate>
</UserControl.Resources>
<!-- IF I MOVE THE CANVAS HERE THE OPACITY CHANGES ON MOUSE OVER -->
Codebehind:
public partial class KeyControl : UserControl
{
private bool _isPressed = false;
private bool _isMouseOver = false;
public KeyControl()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(KeyControl_Loaded);
}
private void KeyControl_Loaded(object sender, RoutedEventArgs e)
{
//this will be set in the Type setter
this.Template = this.FindResource("TemplateSquare") as ControlTemplate;
this.MouseEnter += new MouseEventHandler(CorePart_MouseEnter);
this.MouseLeave += new MouseEventHandler(CorePart_MouseLeave);
GoToState(false);
}
private void GoToState(bool useTransitions)
{
if (_isPressed)
VisualStateManager.GoToState(this, "Pressed", useTransitions);
else if (_isMouseOver)
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
else
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
private void CorePart_MouseLeave(object sender, MouseEventArgs e)
{
_isMouseOver = false;
GoToState(true);
}
private void CorePart_MouseEnter(object sender, MouseEventArgs e)
{
_isMouseOver = true;
GoToState(true);
}
}
Can somebody please tell me where the problem could be?
Thank You
The UserControl makes it's Content the "root" element, which is used to locate the VisualStateGroups. If you use Reflector and look at UserControl.StateGroupsRoot, you'd see it looks like:
internal override FrameworkElement StateGroupsRoot {
get {
return (base.Content as FrameworkElement);
}
}
While FrameworkElement (and thus most other elements) use:
internal virtual FrameworkElement StateGroupsRoot {
get {
return (this._templateChild as FrameworkElement);
}
}
When setting the Template property, the Content property will still be null. When you move the Canvas to be below Resources, you are setting the Content property. So the visual state groups can be found in that case.
You can work around this by changing your control derive from ContentControl directly, and bypass UserControl. Simply change UserControl references to ContentControl in your XAML and code-behind.