Following shows part of my MainWindow.xaml:
<Grid>
<ListBox x:Name="listBox" (Line #40)
ItemsSource="{Binding Rectangles}"
SelectionMode="Extended" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style
TargetType="{x:Type ListBoxItem}" >
<Setter
Property="Canvas.Left"
Value="{Binding X}" />
<Setter
Property="Canvas.Top"
Value="{Binding Y}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Canvas x:Name="dragSelectionCanvas" (Line #64)
Visibility="Collapsed" >
<Border x:Name="dragSelectionBorder" (Line #66)
Opacity="0.5" />
</Canvas>
</Grid>
And this is the corresponding MainWindow.g.i.cs file generated by Visual Studio:
public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
#line 40 "..\..\MainWindow.xaml"
internal System.Windows.Controls.ListBox listBox;
#line 64 "..\..\MainWindow.xaml"
internal System.Windows.Controls.Canvas dragSelectionCanvas;
#line 66 "..\..\MainWindow.xaml"
internal System.Windows.Controls.Border dragSelectionBorder;
(I have deleted some lines for sake of brevity.)
I can see in the .cs file that for every XAML element with an x:Name attribute, Visual Studio generates a corresponding member declaration.
My question: Where are the declarations for those XAML elements, such as the Grid element above as well as the outer Window element (not shown) that do not have an x:Name attribute? Are they declared as well behind the scenes?
They aren't declared anywhere.
XAML code like this:
<Canvas x:Name="dragSelectionCanvas" (Line #64)
Visibility="Collapsed" >
<Border x:Name="dragSelectionBorder" (Line #66)
Opacity="0.5" />
</Canvas>
equals
new Canvas
{
Visibility = Visibility.Collapsed,
Content = new Border { Opacity = 0.5 }
}
You only need a reference to the root control which is this in your xaml.cs class. Things with names are just shortcut references to those object, so that you don't need to go down the logical tree every time.
Once you understand that <SomeClass Property="5"/> == new SomeClass { Property = 5 } everything becomes easier.
For example, in MVVM you set up ViewModel property. You can it in xaml.cs in constructor:
this.ViewModel = new SpecificViewModel() - if it has default contructor
or in xaml:
<MyControl.ViewModel>
<SpecificViewModel/>
</MyControl.ViewModel>
This basically means, that you can contruct fully speced UserControl in only cs file like this:
public class MyControl : UserControl
{
public MyControl()
{
Content = new StackPanel { Content = new TextBlock{ Text = "Sample Text"}};
}
}
Notice that the TextBlock isn't referenced anywhere, but it's still there. Analogical xaml should be now straight forward to write.
You probably noticed the lack off InitializeComponents() call. That's because under the hood it runs the generated from XAML and fills this.Content and sets references to objects with names. No XAML means no need to call this method.
You can find more details here
Related
I am trying to display some images in a ListView and have not been successful. I am using WPF MVVM and the ListView is a holdover from simply displaying suits and rank data. (See my previous post: MVVM in WPF - How to alert ViewModel of changes in Model... or should I? if you are interested!) That is, I could use something other than ListView (if that is the advice) but I would still like to know how to do it with ListView, assuming it's doable. My property I'm binding to in the ViewModel is:
public ObservableCollection<Image> PlayerCardImages{
get{
ObservableCollection<Image> results = new ObservableCollection<Image>();
foreach (CardModel card in PlayerCards)
{
Image img = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
// TODO: Pick card based on suit/rank. Just get 1 image working now
bi3.UriSource = new Uri("diamond-1.png", UriKind.Relative);
bi3.EndInit();
img.Stretch = Stretch.Fill;
img.Source = bi3;
results.Add(img);
}
return results;
}
}
In my XAML code I'm using:
<Window.Resources>
<DataTemplate x:Key="ImageCell">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding PlayerCardImages}" Width="200" Height="200" Stretch="Fill" ToolTip="Add tooltip"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView Name="lvwTitles" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectionMode="Single" ItemTemplate="{StaticResource ImageCell}" Height="59">
</ListView>
</StackPanel>
This idea was shamelessly stolen from: WPF - bind images horizontally to ListView However, it doesn't even appear to databind as evidenced by my breakpoint in PlayerCardImages not being hit.
I also tried the following XAML with somewhat better luck:
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView
AlternationCount="2"
DataContext="{StaticResource PlayerCardsGroups }"
ItemsSource="{Binding}"
>
<ListView.GroupStyle>
<StaticResourceExtension
ResourceKey="CardGroupStyle"
/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn>
<Image Height="50" Width="40"></Image>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
<Window.Resources>
<CollectionViewSource x:Key="PlayerCardsGroups"
Source="{Binding Path=PlayerCardImages}">
</CollectionViewSource>
<GroupStyle x:Key="CardGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock
x:Name="txt"
Background="{StaticResource Brush_HeaderBackground}"
FontWeight="Bold"
Foreground="White"
Margin="1"
Padding="4,2,0,2"
Text="Cards"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="CardItemStyle" TargetType="{x:Type ListViewItem}">
<!--
Stretch the content of each cell so that we can
right-align text in the Total Sales column.
-->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a CustomerViewModel object.
-->
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
this code definitely goes through databinding - my breakpoint is hit at the beginning of the program and whenever items are added to the collection. But no images is displayed. Rather than torture you with more XAML that does not work, perhaps I could ask someone to point me to some code/examples/docs that show how to bind a list of Images to a ListView (or another control if you really feel that ListView is inappropriate). Notice that my collection is the stuff I'm binding to. I notice that with many examples, they are binding to a subproperty. I.e. they may have a collection of albums and for each album they bind to it's property image (see: Showing items as images in a WPF ListView).
Any ideas or help would be much appreciated.
-Dave
Additional info.
Based on suggestions by Clemens, I now have this code for PlayerCardImages:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
//if (PlayerCards.Count == 0)
// return results;
//else
//{
// results.Add(new BitmapImage(new Uri(#"Images\\" + "diamond-1.png", UriKind.Relative)));
//}
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(#"Images\\" + GetCardFileName(card), UriKind.Relative)));
}
return results;
}
I used the exact XAML he suggested. It almost works. I say "almost" because I noticed strange behavior whereby sometimes 1 card would show and sometimes not (I never got 2 cards). All the getting cards from files and binding seems to be working and I tracked down what I think is key to the last remaining bug (and it's BIZARRE). If in the debugger, I examine results, and further open up results[0] in the debugger, I get that card displayed! I actually have to open up [0] (you see info about height, width, etc.) for this to work. Furthermore if I open up [1], I get that card displayed instead. Why would opening up the debugger info have any effect? For those of you who might ask, what happens if you open up both cards in the debugger... that doesn't work. I get a operation timed out exception. I will say that perhaps my image files are big. 10Kbytes to 30 Kbytes. Is that the problem? I'm guessing not, and that it's a subtle problem with reading in the images or binding. What is going on? Thanks, Dave
First, you should not use Image controls in your ViewModel. You already have an Image control in the DateTemplate of your view. You want to bind the Source property of this Image conntrol, and the source property of this binding can't be another Image.
Instead your ViewModel would either use ImageSource (or a derived class like BitmapImage) as image type, like this:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(card.ImageUrl)));
}
return results;
}
}
Or simply the image URIs or paths, as there is an automatic conversion from string to ImageSource built into WPF:
public ObservableCollection<string> PlayerCardImages
{
get
{
var results = new ObservableCollection<string>();
foreach (var card in PlayerCards)
{
results.Add(card.ImageUrl);
}
return results;
}
}
You would now bind your Listbox's ItemsSource property to the PlayerCardGames collection, and in the DataTemplate you bind directly to the collection item. The ListView's DataContext has to be set to an instance of the object that defines the PlayerCardGames property.
<ListView ItemsSource="{Binding PlayerCardGames}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
UPDATE: As there seems to be a problem with loading the image files, you may try the following method. It loads images synchronously and you are able to step through with the debugger.
public static ImageSource LoadImage(string fileName)
{
var image = new BitmapImage();
using (var stream = new FileStream(fileName, FileMode.Open))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
return image;
}
You can use this method in your PlayerCardGames property getter like this:
foreach (var card in PlayerCards)
{
results.Add(LoadImage(#"Images\\" + GetCardFileName(card)));
}
I didn't really try to reproduce your problem, but I will if this is not solving it:
In your first xaml block, I think you mixed up the bindings. This would be how I expect it, ItemsSource to the ObservableCollection of Images, Image source to the Image.
<Image Source="{Binding}" ... />
<ListView Name="lvwTitles" ItemsSource="{Binding PlayerCardImages}" ... />
In your second block, you omitted the Source binding altogether:
<Image Source="{Binding}" Height="50" Width="40" />
The WPF version of this question is here: But it hasn't been answered and I don't know if the UWP TreeView will have the same answer.
I'm trying to add a DataTemplateSelector to the new UWP TreeViews that were just added to windows 10 version 1803 but it isn't working. It is documented here how to use the XAML TreeView Control and even shows how to modify the template to change the Item Datatemplate which works fine. I need to use a datatemplate selector since each of my nodes is using different objects and I need them displayed differently. The TreeView.Node.Content is being set just fine and everything works except it is passing null over to the datatemplateselector in the Object parameter.
Here is my code: (same as the example from Microsoft just with using ItemTemplateSelector)
<Style TargetType="TreeView">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<TreeViewList x:Name="ListControl"
ItemTemplateSelector="{StaticResource CardSelector}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
CanDragItems="True"
AllowDrop="True"
CanReorderItems="True">
<TreeViewList.ItemContainerTransitions>
<TransitionCollection>
<ContentThemeTransition />
<ReorderThemeTransition />
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</TreeViewList.ItemContainerTransitions>
</TreeViewList>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Does anyone have any insight or experience on this? My datatemplateselector "CardSelector" works fine and I have been using it in several places without any trouble.
So the point of my question isn't to get anything that I have working but to see if the TreeViewControl works with a DataTemplateSelector. I only have "CardTemplateSelector" in there because I use it in several other places of my app and I know it works. My question is really a "yes, treeview works with a selector" or "no it doesn't" I'm really looking for someone else to try it with their own test template selector and to let me know if they can get it working. Any specific code from me is not relevant to the question. Just see if you can get it to work with whatever selector you want
Yes. The TreeView work well with ItemTemplateSelector.
I used the all code in the document and create a custom class like the following:
public class Test
{
public string Name { get; set; }
}
I made another DataTemplate like this:
<DataTemplate x:Key="TreeViewObjDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.Name}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
My CardTemplateSelector class is the following:
public class CardTemplateSelector: DataTemplateSelector
{
public DataTemplate TreeViewItemDataTemplate { get; set; }
public DataTemplate TreeViewObjDataTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
TreeViewNode treeViewNode = item as TreeViewNode;
if (treeViewNode.Content is StorageFolder|| treeViewNode.Content is StorageFile)
{
return TreeViewItemDataTemplate;
}
if (treeViewNode.Content is Test)
{
return TreeViewObjDataTemplate;
}
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
I just add the new lines code in MainPage.xaml.cs:
TreeViewNode objnode = new TreeViewNode();
Test test = new Test() {Name="Parent"};
objnode.Content = test;
objnode.IsExpanded = true;
objnode.HasUnrealizedChildren = true;
sampleTreeView.RootNodes.Add(objnode);
The following is the whole xaml page resource code:
<Page.Resources>
<DataTemplate x:Key="TreeViewItemDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.DisplayName}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="TreeViewObjDataTemplate">
<Grid Height="44">
<TextBlock
Text="{Binding Content.Name}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{ThemeResource BodyTextBlockStyle}"/>
</Grid>
</DataTemplate>
<local:CardTemplateSelector x:Name="CardTemplateSelector" TreeViewItemDataTemplate="{StaticResource TreeViewItemDataTemplate}" TreeViewObjDataTemplate="{StaticResource TreeViewObjDataTemplate}"></local:CardTemplateSelector>
<Style TargetType="TreeView">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<TreeViewList x:Name="ListControl"
ItemTemplateSelector="{StaticResource CardTemplateSelector}"
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
CanDragItems="True"
AllowDrop="True"
CanReorderItems="True">
<TreeViewList.ItemContainerTransitions>
<TransitionCollection>
<ContentThemeTransition />
<ReorderThemeTransition />
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</TreeViewList.ItemContainerTransitions>
</TreeViewList>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
So far I have answered your question. But I still want to let you know How to ask a good question. In my above comments, I asked you to provide the relevant code, then I could quickly reproduce your question and help you diagnose it. But you said I'm really looking for someone else to try it with their own test template selector and to let me know if they can get it working.. It's Ok. You could see that only I replied. You asked this question for many days. No other community members helped you on this question. That's why I ask you to post some code here. If you provide the relevant code here, I believe many community members will be glad to help you on this question. I really hope you could understand it.
There seems to be confusion about where to apply the DataTemplate. And the all important TargetType is ignored.
If you want a handle on the data item in your custom DataTemplateSelector, you need to:
OPTION 1
Apply the DataTemplateSelector on TreeView.ItemTemplateSelector
Make sure that the DataTemplates have TreeViewNode as the target type.
Only then the data item of the TreeViewNode is supplied to the SetTemplateCore(object item) and SetTemplateCore(object item, DependencyObject container) overrides of your custom DataTemplateSelector.
A working example is found here: Pictures and Music library tree view
OPTION 2
Apply the DataTemplateSelector on TreeViewItem.ContentTemplateSelector
Make sure that the DataTemplates have [YOUR-DATA-TYPE] as the target type
In the TreeView.ItemTemplate bind the DataContext AND Content property to [YOUR-DATA-TYPE], i.e.
<TreeView.ItemTemplate>
<DataTemplate x:DataType="[YOUR-DATA-TYPE]">
<TreeViewItem DataContext="{Binding}" ... Content="{Binding}">
<TreeViewItem.ContentTemplateSelector>
<YourDataTemplateSelector.TemplateA>
<DataTemplate x:DataType="[YOUR-DATA-TYPE]">
...
// YourDataTemplateSelector
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item == null) return null;
return (([YOUR-DATA-TYPE])item).IsSomething ? TemplateA : TemplateB;
}
I'm trying to simulate the ASP.Net master-page concept (Layout in MVC) on WPF Windows.
I have a CustomWindow class that specifies some behaviors for this sort of Windows:
public class CustomWindow : Window
{
//...
}
And MasterWindowBase; a CustomWindow that takes some sort of my UserControls to be the window content (via style):
public abstract class MasterWindowBase : CustomWindow
{
public MasterWindowBase(MyUserControlBase content)
{
ContentUserControl = content;
Style = Application.Current.FindResource("MasterWindowStyle") as Style;
}
#region ContentUserControl Property
public MyUserControlBase ContentUserControl
{
get { return (MyUserControlBase)GetValue(ContentUserControlProperty); }
set { SetValue(ContentUserControlProperty, value); }
}
public static readonly DependencyProperty ContentUserControlProperty =
DependencyProperty.Register("ContentUserControl", typeof(MyUserControlBase), typeof(MasterWindowBase));
#endregion
}
The style defined in application resources:
<Style x:Key="MasterWindowStyle" TargetType="{x:Type local:MasterWindowBase}">
<Setter Property="Content">
<Setter.Value>
<Grid>
<StackPanel>
<TextBlock Text="This is a master window"/>
<ContentPresenter Content="{Binding ContentUserControl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MasterWindowBase}}}"/>
</StackPanel>
</Grid>
</Setter.Value>
</Setter>
</Style>
And MasterWindow; a generic window used to create an instance of MasterWindowBase with the specified UserControl type:
public class MasterWindow<TMyUserControlBase>
: MasterWindowBase
where TMyUserControlBase : MyUserControlBase, new()
{
public MasterWindow() : base(new TMyUserControlBase()) { }
}
Now for the first Window.Show, everything works perfectly, but then I caught two logical errors:
When I close the Window and show a new instance of it with a different UserControl, it loads the content of the first-shown MasterWindow.
When I show a new instance of MasterWindow either with the same UserControl or with a different one without closing the currently-showing window(s), it clears the content of all the currently-showing MasterWindow instances, and loads the content of the first-shown MasterWindow in the new instance.
Note that I can't use the Template property inside the MasterWindowStyle style because the style is actually based on CustomWindow's style (in the real project) which already use the Template property.
Any help will be appreciated.
The reason of observed behavior is you try to set Content of your window in Style. Because it's not a template - WPF will create a tree with your UserControl only once. Then when you apply this style again and again - the same visual tree (with the same, first, UserControl) is reused every time (and of course one control cannot be used in different parents - so it gets removed from where it is hosted now and moved to the window you apply style to).
Long story short - you just should not setting Content via Style in WPF. To fix your immediate problem, you can just set ContentTemplate property instead of Content, and wrap what you have in DataTemplate (leaving everything else the same). This will fix it, because for templates new visual tree is created every time.
Here is yet another way to fix it, still using Content property, however it looks like kind of a hack and I'd better void doing this (though still works):
<Application.Resources>
<Grid x:Shared="False" x:Key="myControl">
<StackPanel>
<TextBlock Text="This is a master window"/>
<ContentPresenter Content="{Binding ContentUserControl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MasterWindowBase}}}"/>
</StackPanel>
</Grid>
<Style x:Key="MasterWindowStyle" TargetType="{x:Type local:MasterWindowBase}">
<Setter Property="Content">
<Setter.Value>
<StaticResource ResourceKey="myControl" />
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Here you define your visual tree in resources with x:Shared="False" attribute. This attribute means every time this resource is referenced - new instance will be created (by default - same instance is reused). Then you reference this resource inside your Style.
I have a project with a Window Manager using AvalonDock.
Basically there is two Element : a LayoutAnchorableItem to show my different tool box (currently one, consisting of a Treeview) and a LayoutItem to show the document opened with the treeview (a custom control, with bindable parameters - in theory)
The ViewModel of the DockingManager hosts the ObservableCollection named Panes that will be the LayoutItems.
Things works "fine" if I don't try to bind the parameters in the XAML, and force the values like this
<avalonDock:DockingManager.LayoutItemTemplateSelector>
<panes:PanesTemplateSelector>
<panes:PanesTemplateSelector.ExchangeViewTemplate>
<DataTemplate>
<xchng:Exchange/>
</DataTemplate>
</panes:PanesTemplateSelector.ExchangeViewTemplate>
<panes:PanesTemplateSelector.GraphViewTemplate>
<DataTemplate>
<grph:Graph TickerCode="ILD" ExchangeCode="EPA"/>
</DataTemplate>
</panes:PanesTemplateSelector.GraphViewTemplate>
</panes:PanesTemplateSelector>
</avalonDock:DockingManager.LayoutItemTemplateSelector>
Exchange is the toolbox and Graph is the LayoutItems.
The initial databinding for the docking manager is done like this :
<avalonDock:DockingManager Margin="0,0,0,0"
Grid.Row="1"
AnchorablesSource="{Binding Tools}"
DocumentsSource="{Binding Panes}"
ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}"
x:Name="dockManager">
Note that Pane is of type GraphViewModel which has two public parameters : ExchangeCode and TickerCode.
The thing is I want to bind the TickerCode and ExchangeCode to the Panes.TickerCode and Panes.ExchangeCode values.
So I tried this :
<grph:Graph TickerCode="{Binding TickerCode, UpdateSourceTrigger=PropertyChanged}" ExchangeCode="{Binding ExchangeCode, UpdateSourceTrigger=PropertyChanged}"/>
But it does nothing : TickerCode and ExchangeCode in the custom control are equal to "" contrary to when I force the values in the XAML.
Also the somewhat weird thing is that if I step in the code execution, Panes actually have values for TickerCode and ExchangeCode, they just don't bind. For instance, the code that actually create the pane is
public void AddGraph(string FullName, string ExchangeCode, string TickerCode)
{
var graphViewModel = new GraphViewModel(FullName, ExchangeCode, TickerCode);
_panes.Add(graphViewModel);
ActiveDocument = graphViewModel;
}
Here, every step has both values. And let's imagine that I add 5 different panes, they are all with their correct ExchangeCode and TickerCode, but nothing is passed to the custom control.
If you need more info on my custom control that values are bound to, here is the code : Passing parameters to custom control (databinding).
Remark: As you see I didn't put much of my code, make request if you think it may help and I will add what's needed. Note that the global logic of the whole window manager is the same provided in the AvalonDock test app (AvalonDock.MVVMTestApp).
For example, if I’ve got ChartView and ChartViewModel:
In MainWindow.xaml:
<xcad:DockingManager x:Name="dockingManager"
AnchorablesSource="{Binding Path=Anchorables}"
DocumentsSource="{Binding Path=Documents}"
ActiveContent="{Binding Path=ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}">
<xcad:DockingManager.LayoutItemTemplateSelector>
<selfViewPane:PaneTemplateSelector>
<selfViewPane:PaneTemplateSelector.ChartViewTemplate>
<DataTemplate>
<selfViewDocument:ChartView />
</DataTemplate>
</selfViewPane:PaneTemplateSelector.ChartViewTemplate>
</selfViewPane:PaneTemplateSelector>
</xcad:DockingManager.LayoutItemTemplateSelector>
<xcad:DockingManager.LayoutItemContainerStyleSelector>
<selfViewPane:PaneStyleSelector>
<selfViewPane:PaneStyleSelector.ChartViewStyle>
<Style TargetType="{x:Type xcad:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
</Style>
</selfViewPane:PaneStyleSelector.ChartViewStyle>
</selfViewPane:PaneStyleSelector>
</xcad:DockingManager.LayoutItemContainerStyleSelector>
<xcad:DockingManager.LayoutUpdateStrategy>
<selfViewPane:LayoutInitializer />
</xcad:DockingManager.LayoutUpdateStrategy>
<xcad:LayoutRoot>
<xcad:LayoutPanel Orientation="Horizontal">
<xcad:LayoutAnchorablePane Name="ToolsPane" DockWidth="200">
</xcad:LayoutAnchorablePane>
<xcad:LayoutDocumentPane />
</xcad:LayoutPanel>
</xcad:LayoutRoot>
</xcad:DockingManager>
And:
In ChartViewModel I’ve got property ChartPlotModel:
/// <summary>
/// Gets or sets the ChartPlotModel.
/// </summary>
public PlotModel ChartPlotModel
{
get
{
return this.chartPlotModel;
}
set
{
if (this.chartPlotModel != value)
{
this.chartPlotModel = value;
this.RaisePropertyChanged("ChartPlotModel");
}
}
}
In ChartView I can bind:
<UserControl x:Class="Jofta.Analyzer.UI.Classes.View.Document.ChartView"
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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:oxy="http://oxyplot.org/wpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<xctk:BusyIndicator IsBusy="{Binding Path=IsBusy}">
<Grid>
<oxy:PlotView Model="{Binding ChartPlotModel}" />
</Grid>
</xctk:BusyIndicator>
</UserControl>
In this example I’m binding to PlotView from oxyplot, but I think, you can use this pattern. You’ve got GraphViewModel, GraphView and TickerCode and ExchangeCode.
I have a ListBox that its ItemsSource is given from a class based on the data binded items template. I want to find ListBox.SelectedItem position relative to the ListBox. Since I've used a class to feed ItemsSource, I'm not be able to cast ListBox.SelectedItem (which has a type of object) to the ListBoxItem. (Instead I should cast it to the source class type.)
What's the way? -Thanks
Details: (Arbitrary)
There is a ListBox which implements a Style like so:
<Style x:Key="MyListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border ...>
<StackPanel ...>
<Image Source="{Binding Path=ItemImageSource}" .../>
<TextBlock Text="{Binding Path=ItemTitle}" .../>
</StackPanel>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The ListBox has been used as follows:
<ListBox x:Name="MyListBox"
ItemsSource="{Binding}"
Style="{StaticResource ResourceKey=MyListBoxStyle}"/>
Also there is a class that supports MyListBox data-binding info:
internal class MyListBoxItemBinding
{
public string ItemTitle { get; set; }
public ImageSource ItemImageSource { get; set; }
}
And to feed the MyListBox:
MyListBox.ItemsSource = new List<MyListBoxItemBinding> { /* some items */ };
Now, how can I find MyListBox.SelectedItem location relative to the MyListBox?
Use ItemsControl.ItemContainerGenerator to get a reference to the item container generator for your ListBox (this is the object that creates wrappers for all your databound objects).
Then, use the ItemContainerGenerator.ContainerFromItem method to get a reference to the UIElement that represents the selected ListBoxItem.
Finally, see the answer to this question to for a way of getting the coordinates of the selected item relative to the ListBox.