I am loading values for a listbox from an xml file. What my problem is i can't get the bindings show the property values of the class that each item is assigned. When i set the Text this way:
<TextBlock Text="{Binding }" Style="{StaticResource TitleBlock}"></TextBlock>
The items show the toString value of the class, but if i use:
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleBlock}"></TextBlock>
I get blank space for each Item in the list box. I hope i have explained my problem well enough. Code posted below:
MapList.xml
<Maps>
<map>
<title>Backlot</title>
<id>mp_backlot</id>
<description>Daytime urban combat.</description>
<thumbnail>mapImages/map11.jpg</thumbnail>
</map>
<map>
<title>Bloc</title>
<id>mp_bloc</id>
<description>Snowy close quarters combat with some sniping available.</description>
<thumbnail>mapImages/map11.jpg</thumbnail>
</map>
<map>
<title>The Bog</title>
<id>mp_bog</id>
<description>Night time map great for any play style.</description>
<thumbnail>mapImages/map11.jpg</thumbnail>
</map>
</Maps>
MainPage.xaml :
<UserControl
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:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" x:Class="Cod4ServerTool.MainPage" Height="521" Width="928">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Background>
<ImageBrush Stretch="Uniform" ImageSource="ui_bg.jpg"/>
</Grid.Background>
<controls:TabControl Margin="0,8,0,0" Grid.Row="1">
<controls:TabControl.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="#662A2C12" Offset="1"/>
</LinearGradientBrush>
</controls:TabControl.Background>
<controls:TabItem Header="TabItem" Foreground="Black">
<Grid>
<ListBox x:Name="MapsList_lb" Margin="8,8,177,8">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ThumbNail}" Style="{StaticResource ThumbNailPreview}"></Image>
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleBlock}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#66F0F2F0" Offset="0.254"/>
<GradientStop Color="#CC828C82" Offset="1"/>
<GradientStop Color="#CCD5DED6"/>
</LinearGradientBrush>
</ListBox.Background>
</ListBox>
<ListBox Margin="0,8,8,8" HorizontalAlignment="Right" Width="160">
<ListBox.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#66F0F2F0" Offset="0.254"/>
<GradientStop Color="#CC828C82" Offset="1"/>
<GradientStop Color="#CCD5DED6"/>
</LinearGradientBrush>
</ListBox.Background>
</ListBox>
</Grid>
</controls:TabItem>
<controls:TabItem Header="TabItem">
<Grid/>
</controls:TabItem>
</controls:TabControl>
<Button Height="21" HorizontalAlignment="Right" Margin="0,8,8,0" VerticalAlignment="Top" Width="95" Content="Import Maps" Grid.Row="1" Click="Button_Click"/>
</Grid>
</UserControl>
the .cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
namespace Cod4ServerTool
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DisplayMaps("MapList.xml");
}
private void DisplayMaps(string xmlContent)
{
XDocument xmlMaps = XDocument.Load(xmlContent);
var maps = from map in xmlMaps.Elements("Maps").Elements("map")
select new Map
{
Id = map.Element("id").Value,
Title = map.Element("title").Value,
Description = map.Element("description").Value,
ThumbNail = map.Element("thumbnail").Value,
};
MapsList_lb.SelectedIndex = -1;
MapsList_lb.ItemsSource = maps;
}
}
}
Map.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Cod4ServerTool
{
class Map
{
public string Title { get; set; }
public string Id { get; set; }
public string Description { get; set; }
public string ThumbNail { get; set; }
public override string ToString()
{
return Title;
}
}
}
I would make the maps variable into a List by just adding .ToList();
private void DisplayMaps(string xmlContent)
{
XDocument xmlMaps = XDocument.Load(xmlContent);
var maps = (from map in xmlMaps.Elements("Maps").Elements("map")
select new Map
{
Id = map.Element("id").Value,
Title = map.Element("title").Value,
Description = map.Element("description").Value,
ThumbNail = map.Element("thumbnail").Value,
}).ToList();
MapsList_lb.SelectedIndex = -1;
MapsList_lb.ItemsSource = maps;
}
Edit:
D'oh! and your Map class needs to be declared public. Binding doesn't work with internal types.
The above advice to use ToList still stands, its better for ItemsSource to reference a simple List<Map> than it is to reference a LINQ query that in turns holds on to a tree of XObjects.
Implement interface INotifyPropertyChanged of Map class:
public class Map : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _Title;
public string Title
{
get { return _Title; }
set
{
_Title = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Title"));
}
}
}
...
}
It will work fine after that.
Update:
Make Map class public.
Related
I am using Caliburn, ninject
I want to create a plane Cockpit with a background image (inside grid)
and add dynamically (following the type of plane) lot of usercontrol (like lamps, switches or gauges at different position)
I know to add dynamically Usercontrol behind code (Grid.Add.Children)
but is it possible with Caliburn , using convention names and stay in MVVM? or I have to used code behind.. I have no idea to take the problem.
File: BootStrapper.cs
using System;
using System.Collections.Generic;
using System.Windows;
using Caliburn.Micro;
using Ninject;
using WpfApp2.ButtonAndSwitches;
namespace WpfApp2.Bootstrap
{
public class Bootstrapper : BootstrapperBase
{
private IKernel kernel;
public Bootstrapper()
{
Initialize();
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
}
protected override void Configure()
{
kernel = ServiceBootstrapper.Create();
kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
kernel.Bind<MainWindowViewModel>().ToSelf().InSingletonScope();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<MainWindowViewModel>();
}
private void OnSettingsLoaded()
{
}
protected override object GetInstance(Type service, string key)
{
return kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return kernel.GetAll(service);
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
kernel.Get<ILog>().Error(e.ExceptionObject as Exception);
}
}
public static class ServiceBootstrapper
{
public static IKernel Create()
{
var kernel = new StandardKernel();
BindCommon(kernel);
return kernel;
}
private static void BindCommon(StandardKernel kernel)
{
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
}
}
}
InstrumentsViewModel.cs
using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using WpfApp2.ButtonAndSwitches;
using WpfApp2.CommonEvents;
using WpfApp2.Extensions;
using IEventAggregator = WpfApp2.Events.IEventAggregator;
namespace WpfApp2
{
public class InstrumentsViewModel : Screen
{
private bool show;
private InstrumentsView instrumentsview;
private MainWindowViewModel mainwindow;
private readonly IEventAggregator eventAggregator;
private readonly int panel;
private readonly IWindowManager windowmanager;
private string _backgroundFile;
public InstrumentsViewModel(IEventAggregator eventAggregator, IWindowManager windowmanager, int panel)
{
this.panel = panel;
this.eventAggregator = eventAggregator;
this.windowmanager = windowmanager;
}
protected override void OnViewReady(object view)
{
if (panel == 0)
{
instrumentsview = view as InstrumentsView;
RenderOptions.ProcessRenderMode = System.Windows.Interop.RenderMode.SoftwareOnly;
var backgroundFilestring = #"F:\Ikarus-master\Ikarus\Images\Backgounds\A10CBackGround.png";
BackImage = (backgroundFilestring);
UserControl userControl = (UserControl)Activator.CreateInstance(Type.GetType("WpfApp2.ButtonAndSwitches.SwitchOn_Off_OnView"));
instrumentsview.MainGrid.Children.Add(userControl);
}
}
public string BackImage
{
get => _backgroundFile;
set
{
_backgroundFile = value;
NotifyOfPropertyChange(() => BackImage);
}
}
public void ButtonClose()
{
instrumentsview.Close();
}
public void BackImage_GotFocus()
{
}
public void Window_MouseMove()
{
}
public void Window_MouseDown()
{
}
public void Window_GotFocus()
{
}
}
}
Sample of Switch
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Caliburn.Micro;
using WpfApp2.CommonEvents;
namespace WpfApp2.ButtonAndSwitches
{
public class SwitchOn_Off_OnViewModel:Screen
{
private string pictureUp = "";
private string pictureMiddle = "";
private string pictureDown = "";
private int state = 1;
public SwitchOn_Off_OnViewModel()
{
SwitchMiddle = #"F:\Ikarus-master\Ikarus\Images\Switches\switch_mid2.png";
}
private string _Switchmiddle;
public string SwitchMiddle
{
get
{
return _Switchmiddle;
}
set
{
_Switchmiddle = value;
NotifyOfPropertyChange(() => SwitchMiddle);
}
}
public void Light_MouseWheel()
{
}
public void UpperRec_MouseDown()
{
if (++state > 2) state = 2;
SetValue(state, true);
}
public void UpperRec_MouseUp()
{
SetValue(1, true);
}
public void LowerRec_MouseDown()
{
if (--state < 0) state = 0;
SetValue(state, true);
}
public void LowerRec_MouseUp()
{
SetValue(1, true);
}
private void SetValue(int _state, bool _event, bool dontReset = false)
{
if (_state == 2)
{
}
if (_state == 1)
{
}
if (_state == 0)
{
}
}
}
}
Now all view associated
<Window x:Class="WpfApp2.MainWindowView"
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:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="MainWindowView" Height="158.241" Width="206.594" >
<Grid>
<Button x:Name="ShowOrCloseCockpit" Content="{Binding showorclose}" HorizontalAlignment="Left" Margin="28,29,0,0" VerticalAlignment="Top" Width="112" Height="50"/>
</Grid>
</Window>
<Window x:Class="WpfApp2.InstrumentsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="clr-namespace:WpfApp2.ButtonAndSwitches"
Title="Instruments"
Width="1920"
Height="1080"
AllowsTransparency="True"
Background="Transparent"
cal:Message.Attach="[Event GotFocus] = [Action Window_GotFocus()];[Event Mousedown] = [Action Window_MouseDown()];[Event MouseMove] = [Action Window_MouseMove()]"
Topmost="True"
WindowStyle="None">
<Border Background="Transparent"
BorderBrush="#00FFA500"
BorderThickness="0"
CornerRadius="0">
<Grid x:Name="MainGrid"
Background="#00060606"
Opacity="1.0">
<Image x:Name="BackImage" cal:Message.Attach="[Event GotFocus] = [Action BackImage_GotFocus()]"
Margin="0,0,0,0"
Stretch="Fill" />
<Button x:Name="btCloseRight"
cal:Message.Attach="[Event Click] = [Action ButtonClose()]"
Width="25"
Height="24"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Content="X"
Foreground="#FF190301"
RenderTransformOrigin="0.895,7.292">
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#FFF3F3F3" />
<GradientStop Offset="0.5" Color="#FFEBEBEB" />
<GradientStop Offset="0.5" Color="#FFDDDDDD" />
<GradientStop Offset="1" Color="#FFAFAC68" />
</LinearGradientBrush>
</Button.Background>
</Button>
<TextBlock x:Name="MousePosition" HorizontalAlignment="Left" Margin="300,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="#FFFBF8F8"/>
</Grid>
</Border>
</Window>
and the Switch View
<UserControl x:Class="WpfApp2.ButtonAndSwitches.SwitchOn_Off_OnView"
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:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="70" cal:Message.Attach="[Event MouseWheel]=[Light_MouseWheel]">
<Grid Name="Switch" RenderTransformOrigin="0.5,0.5">
<Image x:Name="SwitchUp"
Width="70"
Height="150"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<Image x:Name="SwitchMiddle"
Width="70"
Height="150"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<Image x:Name="SwitchDown"
Width="70"
Height="150"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<Rectangle x:Name="UpperRec" cal:Message.Attach="[Event Mousedown]=[UpperRec_MouseDown];[Event MouseUP]=[UpperRec_MouseUp]"
Width="60"
Height="50"
Margin="5,20,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="#00EEDB21"
Stroke="#00000000" />
<Rectangle x:Name="LowerRec" cal:Message.Attach="[Event Mousedown]=[LowerRec_MouseDown];[Event MouseUP]=[LowerRec_MouseUp]"
Width="60"
Height="50"
Margin="5,80,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="#00EEDB21"
Stroke="#00000000"/>
<Rectangle x:Name="DesignFrame"
Width="70"
Height="150"
Margin="0,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="#00EEDB21"
Stroke="#FFF38501"
StrokeThickness="4" />
</Grid>
</UserControl>
when I click on button from Mainview, i launch via windowsManager the instrumentsView
the problem is to add dynamically the switch (more then) onside the view instruments... how I could load the usercontrol and bind with the view (Caliburn??)
Sample of background image
Sample of Switch
I have looked around at the other questions that relate to the DependencyProperty.UnsetValue in IMultiValueConverter, but I havent found an answer that relates to my problem, I think, so here goes:
The problem is Im getting "DependencyProperty.UnsetValue" whatever I try to do with the DataContext.
I have a WPF usercontrol, and in the constructor I create an object, like this:
public partial class Misc_Vehicles_GpsTrackBarContext : UserControl
{
private TimeLine TheTimeLine { get; set; }
public Misc_Vehicles_GpsTrackBarContext()
{
InitializeComponent();
DateTime start = DateTime.Now.AddDays(-1);
TheTimeLine = new TimeLine(start, DateTime.Now);
TheTimeLine.GpsLocations.Add(new GPSLocation(55.13, 13.7, start));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.14, 13.6, start.AddMinutes(3)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.15, 13.5, start.AddHours(6)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.16, 13.4, start.AddHours(9)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.17, 13.3, start.AddHours(12)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.18, 13.2, start.AddHours(15)));
this.DataContext = this;
}
}
Note: I am now expecting the XAML to be able to access the TheTimeLine (like here http://www.wpf-tutorial.com/data-binding/using-the-datacontext/)
So, the "TheTimeLine" is an object that has some relevant data and the object I want to use when I in the XAML file want to "iterate through" the GPS positions:
class TimeLine
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public TimeSpan Duration
{
get
{
return TimeEnd.Subtract(TimeStart);
}
}
public ObservableCollection<GPSLocation> GpsLocations { get; set; } = new ObservableCollection<GPSLocation>();
public TimeLine(DateTime start, DateTime end)
{
if (start > end)
throw new ArgumentOutOfRangeException("The start parameter cannot be greater than the end parameter");
TimeStart = start;
TimeEnd = end;
}
}
class DriverSession
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public TimeSpan Duration
{
get
{
return TimeEnd.Subtract(TimeStart);
}
}
public DriverSession(DateTime start, DateTime end)
{
if (start > end)
throw new ArgumentOutOfRangeException("The start parameter cannot be greater than the end parameter");
TimeStart = start;
TimeEnd = end;
}
}
And, lastly, the XAML. AS can bee seen, the Binding tags under ItemsControl below use values from both TheTimeLine (TimeStart and TimeEnd) which is the same for each GPSPosition, and then uses the ReceivedTime that is in GPSLocation:
<UserControl
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:tWorks.Alfa.OperatorClient.UserControls.Vehicles"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" x:Class="tWorks.Alfa.OperatorClient.UserControls.Vehicles.Misc_Vehicles_GpsTrackBarContext"
mc:Ignorable="d"
d:DesignHeight="260" Width="764.029">
<UserControl.Resources>
<LinearGradientBrush x:Key="HourBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF3EB1EA" Offset="0" />
<GradientStop Color="#FF61BFF1" Offset="0.5" />
<GradientStop Color="#FF01A1F4" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="MinuteBrush" EndPoint="0.999,0.51" StartPoint="0.045,0.51">
<GradientStop Color="#FFEDA25E" Offset="0" />
<GradientStop Color="#FFEDA25E" Offset="0.15" />
<GradientStop Color="#FFFA7A05" Offset="1" />
</LinearGradientBrush>
<local:MarginLengthConverter x:Key="mEventLengthConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Rectangle Fill="AliceBlue"></Rectangle>
<Grid Grid.Row="1">
<Rectangle Margin="0" Height="2" Fill="{DynamicResource HourBrush}"/>
<!-- **** HERE IS THE ItemsControl! **** -->
<ItemsControl x:Name="GpsLocations" ItemsSource="{Binding Path=TheTimeLine.GpsLocations}">
<ItemsPanelTemplate>
<Grid x:Name="EventContainer" Height="20" Background="Gainsboro"/>
</ItemsPanelTemplate>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<!-- **** My rectangles (lines) to draw where I have GPS positions **** -->
<Rectangle StrokeThickness="0" Width="1" Fill="{DynamicResource MinuteBrush}">
<Rectangle.Margin>
<MultiBinding Converter="{StaticResource mEventLengthConverter}">
<Binding Path="TheTimeLine.TimeStart"/> <!-- when DataContext is set to "this", i expected TheTimeLine to be accessible? -->
<Binding Path="TheTimeLine.TimeEnd"/>
<Binding Path="ReceivedTime"/> <!-- ReceivedTime is inside an object called GPSLocation, that I am iterating through -->
<Binding ElementName="EventContainer" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Margin>
</Rectangle>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
And lastly, the annoying error =)
UPDATE
After I updated according to #mm8 comments, I now see this:
So, the values from the "TheTimeLine" fails...
The XAML part regarding the ItemsControl:
<!-- **** HERE IS THE ItemsControl! TheTimeLine.GpsLocations contains GPSLocation objects that has the ReceivedTime used below **** -->
<ItemsControl x:Name="GpsLocations" ItemsSource="{Binding Path=TheTimeLine.GpsLocations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid x:Name="EventContainer" Height="20" Background="Gainsboro"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<!-- **** My rectangles (lines) to draw where I have GPS positions **** -->
<Rectangle StrokeThickness="0" Width="1" Fill="{DynamicResource MinuteBrush}">
<Rectangle.Margin>
<MultiBinding Converter="{StaticResource mEventLengthConverter}">
<Binding Path="TimeStart" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
<Binding Path="TimeEnd" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
<Binding Path="ReceivedTime"/> <!-- ReceivedTime is inside an object called GPSLocation, ObservableCollection<GPSLocation> -->
<Binding ElementName="EventContainer" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Margin>
</Rectangle>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can only bind to public properties:
public TimeLine TheTimeLine { get; set; }
Besides, the DataContext of an element in the ItemTemplate is a GPSLocation object assuming you have bound the ItemsSource property to an IEnumerable<GPSLocation>. If you want to bind to the TheTimeLine property of the parent UserControl class, you could use a RelativeSource:
<Binding Path="TheTimeLine.TimeStart" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
I want to make a custumized Image Control like MSN with Green light in border
You should use a ContentControl with a custom template. And set the content of the control to the image you want to display.
<ContentControl Template="{DynamicResource TheTemplate}"><Image/></ContentControl>
Then define the style somewhere in your resource dictionary.
<ControlTemplate TargetType="{x:Type ContentControl}">
<Grid>
<!-- Add some fancy borders and colors here -->
<ContentPresenter/>
</Grid>
</ControlTemplate>
I would recommend a UserControl, something like this:
<UserControl x:Class="Test.UserControls.BorderedImageControl"
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"
mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Border CornerRadius="{Binding CornerRadius}" Padding="{Binding BorderThickness}" BorderThickness="1">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFE5E5E5" Offset="0"/>
<GradientStop Color="#FF15A315" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="#FF67FF68" Offset="1"/>
<GradientStop Color="#FF75E476" Offset="0.496"/>
<GradientStop Color="#FF0FC611" Offset="0.509"/>
</LinearGradientBrush>
</Border.Background>
<Border.Child>
<Image Source="{Binding Source}"/>
</Border.Child>
</Border>
</UserControl>
namespace Test.UserControls
{
public partial class BorderedImageControl : UserControl
{
public static readonly DependencyProperty SourceProperty = Image.SourceProperty.AddOwner(typeof(BorderedImageControl));
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty = Border.CornerRadiusProperty.AddOwner(typeof(BorderedImageControl));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, CornerRadius); }
}
public static readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(BorderedImageControl), new UIPropertyMetadata(new Thickness()));
public Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
public BorderedImageControl()
{
InitializeComponent();
}
}
}
This is comparatively simple, if you want those custom curved shapes you probably need to work with paths instead of a border with corner radius.
Usage example:
<uc:BorderedImageControl Source="http://www.gravatar.com/avatar/c35af79e54306caedad37141f13de30c?s=32&d=identicon&r=PG"
CornerRadius="20" BorderThickness="10" MaxWidth="100" Margin="5"/>
Looks like this:
See the following code,
After I clicked the button, the listbox render several times.
How can I prevent Listbox flickering?
Is it possible to tell a control stop update/render?
<UserControl x:Class="SilverlightApplication52.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"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="LayoutRoot"
Background="Gray"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ListBox x:Name="listbox"
Background="White"
Margin="100">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}"
Height="{Binding Height}"
Fill="{Binding Background}"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding Scale}"
ScaleY="{Binding Scale}" />
<RotateTransform Angle="{Binding Angle}" />
<TranslateTransform X="{Binding Left}"
Y="{Binding Top}" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="test"
Width="50"
Height="50"
Click="Button_Click" />
</Grid>
public partial class MainPage : UserControl
{
public class ItemInfo
{
public double Left { get; set; }
public double Top { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Angle { get; set; }
public double Scale { get; set; }
public Brush Background { get; set; }
}
ObservableCollection<ItemInfo> _items = new ObservableCollection<ItemInfo>();
public MainPage()
{
InitializeComponent();
listbox.ItemsSource = _items;
}
Random random = new Random();
private void Button_Click(object sender, RoutedEventArgs e)
{
_items.Clear();
for (int i = 0; i < 2000; i++)
{
byte r = (byte)(random.NextDouble()*255);
byte g = (byte)(random.NextDouble()*255);
byte b = (byte)(random.NextDouble()*255);
_items.Add(
new ItemInfo
{
Left = random.NextDouble() * 500,
Top = random.NextDouble() * 500,
Width = random.NextDouble() * 1000,
Height = random.NextDouble() * 1000,
Angle = random.NextDouble() * 359,
Scale = random.NextDouble() * 1,
Background = new SolidColorBrush(Color.FromArgb(255,r,g,b)),
}
);
}
}
}
Try adding to a separate ObservableCollection in that loop (that is not referenced/bound to the listbox). Then when the loop is done assign the listbox ItemsSource to the new observablecollection.
My problem is certainly right on my face but I can't see it...
I am building a very simple user control - a 3D ellipse - and I expose two properties: LightColor and DarkColor. I need to bind these properties to the gradient in my user control, but it is not showing any color at all. Here's my usercontrol:
<UserControl
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:local="clr-namespace:TestBrushes"
mc:Ignorable="d"
x:Class="TestBrushes._3DEllipse"
x:Name="UserControl"
d:DesignWidth="200" d:DesignHeight="200">
<Grid x:Name="LayoutRoot">
<Ellipse Name="MainEllipse" Stroke="{x:Null}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.1">
<GradientStop Color="{Binding ElementName=UserControl, Path=LightColor}" Offset="1"/>
<GradientStop Color="{Binding ElementName=UserControl, Path=DarkColor}" Offset="0"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Name="TopReflectionEllipse" Stroke="{x:Null}" Margin="38,0,38,0" VerticalAlignment="Top" Height="90">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0" CenterX="0.5" CenterY="0.5"/>
<RotateTransform Angle="0" CenterX="0.5" CenterY="0.5"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#A5FFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</UserControl>
and here's my code-behind:
public partial class _3DEllipse
{
public _3DEllipse()
{
InitializeComponent();
}
public Color DarkColor { get; set; }
public Color LightColor { get; set; }
}
If I assign colors as opposed to the binding shown in the code, it works ok, but I want to use the properties I am exposing. What am I doing wrong?
Thanks!
Your issue is likely that you aren't notifiying the UserControl of changes made to the value of the DarkColor and LightColor properties. To do so you'll need to implement the INotifyPropertyChanged interface. The purpose of this interface is to make UI components aware of when the value they're bound to is updated; they subscribe to the PropertyChanged event that is exposed by implementing the interface.
A sample implementation is below, I've left the DarkColor property alone, but it would be updated in the same fashion.
public partial class _3DEllipse : INotifyPropertyChanged
{
private Color _lightColor;
public _3DEllipse()
{
InitializeComponent();
}
// interface implementation
public event PropertyChangedEventHandler PropertyChanged;
public Color DarkColor { get; set; }
public Color LightColor
{
get { return _lightColor; }
set
{
// only update value if its changed
if ( _lightColor == value )
{
return;
}
_lightColor = value;
OnPropertyChanged("LightColor");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if ( PropertyChanged == null ) return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}