I want use the MahApps PanoramaControl to display a bunch of photo's. However I see only the string paths appear in the control, which will be correct if you look at my code.
But I can't figure out howto get it working to show the images instead of the links.
Xaml:
<Controls:Panorama Grid.Row="2"
Grid.ColumnSpan="4"
ItemBox="140"
ItemsSource="{Binding PhotoCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
ViewModel:
string[] filePaths = Directory.GetFiles(#"D:\Google Drive\Images\Backgrounds");
test = new PanoramaGroup("My Photo's", filePaths);
PhotoCollection = new ObservableCollection<PanoramaGroup> { test };
Anyone an idea on how to make it show the images? The control is load as I can scroll sideways on the text.
There is not much documentation on their site on how to get it working...
Or are you using some other Metro style lib for the 4.0 framework?
In order to get MahApps Panorama control i would offer the follow solution below. As to other frameworks that provide this level of detailed MODERN UI experience I have not come across any but interested to know if you do.
Hope the solutions works for you.
You need to add a Data Template the represent the object you're showing.
Start off by defining the object in a POCO class (as illustrated below). Then in the population of the items ensure you translate them to the newly created POCO object instead of leaving them as string values.
public class Photo {
public string Path { get; set; }
}
Next in the definition of you XAML window you need to create a reference to the namespace where the POCO object resides.
xmlns:model="clr-namespace:project.models;assembly=project"
Last, but not least, you want to then create a DataTemplate to represent the object. This is added to the window resources.
<Window.Resources>
<DataTemplate DataType="{x:Type model:Photo}">
<Image Source="{Binding Path}"/>
</DataTemplate>
</Window.Resources>
This should then let the render take place in the interface where it belongs. Hope this works for you.
Related
I need to wrap a datatemplate in a datatemplate that gets built at run time. The wrapped datatemplate is WPF element where as the wrapping template needs to be created in code.
Something like:
public DataTemplate GetTemplate(DataTemplate template)
{
string xaml = string.Format(#"
<DataTemplate>
<ContentControl Content=""{{Binding}}"">
<ContentControl.ContentTemplate>
{0}
</ContentControl.ContentTemplate>
</ContentControl>
</DataTemplate>", template);
return CreateTemplate(xaml);
}
Obviously my datatemplate is more complicated then the one I'm using above.
I dont know of anyway to take an existing xaml element and convert it to a string. It seems like I might be able to use FrameworkElementFactory but I see it is depricated, which leads me to think I'm missing something obvious.
EDITED ---
What I'm doing is creating a control that users will supply a datatemplate but I need to make changes to the the template. Maybe this example will make more sense...
public DataTemplate GetTemplate2()
{
// this template would be supplied by the user
// I'm creating it here as an example
string t = string.Format(#"
<DataTemplate>
<TextBlock Text=""{{Binding Value}}""/>
</DataTemplate>");
T = CreateTemplate(t);
string xaml = string.Format(#"
<DataTemplate>
<ContentControl Content=""{{Binding}}"">
<ContentControl.ContentTemplate>
{0}
</ContentControl.ContentTemplate>
</ContentControl>
</DataTemplate>", t);
return CreateTemplate(xaml);
}
This all works because I'm using the string template (e.g. t). However I need to figure out some way to do it with the actual DataTemplate (e.g. T). Unfortunately XamlWriter can't deal with the Binding.
You can create a DataTemplate selector. There you can add your logic to build your DataTemplate at runtime. Also you can create a dependencyProperty in your DataTemplate selector. Then bind it in your xaml to a DataTemplate stored in some backing model, and there do what ever ...
This link might be a good place to start
You can use XamlWriter (the analog to XamlReader) but it has limitations on what can be properly serialized. Things like event handlers and x:Names cause issues.
**UPDATE
Seeing the additional detail I think you should try reversing your approach. Rather than combining the templates using strings and then trying to turn that into the object you want, you can avoid all the weird parsing restrictions by just creating the user's template as a DataTemplate object and then building your own DataTemplate object around it. Your example code is also using 2 Value Paths, which is going to give you .Value.Value on the inner template Text so check to make sure on your real one that you're ending up with the Paths you want. Here's the basics of your example using the objects instead, with the paths updated to expect a String and display its length:
DataTemplate T = XamlReader.Parse(string.Format(#"
<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<TextBlock Text=""{{Binding}}""/>
</DataTemplate>")) as DataTemplate;
FrameworkElementFactory controlFactory = new FrameworkElementFactory(typeof(ContentControl));
controlFactory.SetBinding(ContentControl.ContentProperty, new Binding("Length"));
controlFactory.SetValue(ContentControl.ContentTemplateProperty, T);
DataTemplate mainTemplate = new DataTemplate { VisualTree = controlFactory };
I am developing an Application with the following layout,
I have no knowledge of MVVM and I'm on a tight timeline.
The Red area on the right is a ContentControl.
The area on the left will be a sidebar for Navigation
My question is
should I follow this aproach
http://channs.blogspot.com/2010/09/wpf-navigation.html OR
should I use MVVM light / Prism OR
should I use WPF pages?
I am currently inclined to option 1. Are there any pros and cons to it?
Which option would you recommend ?
My application will always have only one developer i.e. Me and it will contain about 30 screens.
Since you're on a tight schedule and have no knowledge of MVVM (or Prism?), then you'll be way better off using options 3 and 1. From my experience, it takes devs a long time to get up to speed on MVVM and Prism. Certain things that are taken for granted, become much more difficult in the MVVM/Prism world.
With that being said, I'm a huge advocate of MVVM/Prism and feel that it's well worth the extra effort, especially for a project of your size. However, since you're pressured for time, don't bother, just do code-behind.
Prism takes time to learn, if you are on a tight deadline then I think you should just go with what you know, When you have time reading the prism book especially the section on navigation will be helpful.
Don't go with PRISM,that would be an overkill for such non complex apps. If you are familiar with DataBinding, that can save you a lot of time even without MVVM.Since you're in a hurry, I think you should go with what you already know and start learning MVVM at ease.Good luck
mvvm is not that hard. in your case you need first a mainviewmodel.
public class MainViewModel
{
private ICollectionView _myView {get;set;}
public ObservableCollection<MyModulWrapper> MyModules{get;set;}
public MyModulWrapper SelectedModul {get;set;}
public MainViewModel()
{
this.MyModules = new ObservableCollection<MyModulWrapper>();
//i use icollectionview because i often need sorting or filtering
this._myView = = CollectionViewSource.GetDefaultView(this.MyModules);
this._myView .CurrentChanged += (s, e) => { this.SelectedModul = this._myView .CurrentItem as MyModulWrapper; };
}
}
you have to fill(in any way - i use mef for my apps, but hardcoded its also ok) your collection with all modules(viewmodels) you wanna show on your top screen.
the MyModulWrapper just contain the viewmodel for your modul and a nice display name for your navigation.
public class MyModulWrapper
{
public string Displayname {get;set;}
public object Modul {get;set;}//instead of object you can take an interface or base class or whatever
}
now you have all to let the mainview run :) you just have to set the datacontext for the MainWindow to your MainViewModel.
mainwindow.xaml
<Window.Resources>
<!--for each viewmodel you wanna show create a datatemplate. so wpf knows how to render your viewmodel-->
<DataTemplate DataType={x:Type local:MyViewmodel4FirstButton>
<local:MyFirstButtonView />
</DataTemplate>
</Window.Resources>
<!-- for navigation -->
<ListBox ItemsSource="{Binding MyModules}"
SelectedItem="{Binding SelectedModul , Mode=OneWay}"
IsSynchronizedWithCurrentItem="true">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Displayname}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- all you need to show your selected modul - if you have a DATATEMPLATEs!! -->
<ContentControl Content="{Binding SelectedModul }"/>
all your viewmodels have to implement INotifyPropertyChanged of course, and raise it properly.
ps: code is written without IDE so ignore errors^^
Still picking my way through learning XAML/WPF. If someone can show me how to accomplish the following - it will go a long way to helping me develop my next project (and several similar projects down the road).
Say I have a collection of objects that defines objects to be drawn on a canvas. The objects contain all the information necessary to render the objects, including the shape, color, and location. Can a XAML control be created that binds to this collection and handles the rendering, or is this better done by drawing on the canvas in the code-behind?
One other point - the objects must eventually be click-selectable, selectable via rectangle-lasso, and draggable. This doesn't have to be solved in the example code someone supplies, but I thought it might be relevant to know this as it might affect the various implementations.
Example class below. thanks in advance.
Class DrawingElement
readonly property Shape as string ("circle", "square", "triangle")
readonly property Position as point (coordinates)
readonly property Color as string ("red", "blue", "yellow")
end class
Sub Main
dim lst as new List(of DrawingElement)
lst.add(new DrawingElement("Circle", 10,20, "Blue"))
lst.add(new DrawingElement("Square", 80,35, "Red"))
lst.add(new DrawingElement("Triangle", 210,120, "Yellow"))
<draw lst!>
End Sub
Can be done, but not by using magic strings (e.g., "circle") like in your example.
First, you should be designing your models based on existing framework elements rather than designing the model with the idea of whipping up some new UI elements or struggling to create code that interprets between them.
WPF already has an ellipse (circle), rectangle (square) and a whole host of other geometric primitives for you to use. You'll want to create models that contain public bindable properties that you can bind to instances of these elements to control their shape and location.
Without going into much detail (or testing), I'd do something like this
public class GeometricElement : INotifyPropertyChanged
{
// these are simplified and don't show INPC code
public double Left {get;set;}
public double Top {get;set;}
public Brush Fill {get;set;}
// ...
}
// ...
public class Square : GeometricElement
{
public double Width {get;set;}
public double Height {get;set;}
}
// ...
// bound to the window
public class CadAppDataContext
{
public ObservableCollection<GeometricElement> Elements {get; private set;}
}
And in my xaml, it would look something like
<ItemsControl ItemsSource="{Binding Source={StaticResource cadAppDataContext}}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate TargetType="{x:Type me:Square}">
<Rectangle
Canvas.Left="{Binding Left}"
Canvas.Top="{Binding Top}"
Width="{Binding Width}"
Height="{Binding Height}"
Fill="{Binding Fill}" />
</DataTemplate>
<!-- more DataTemplates for circle, triangle, etc etc -->
</ItemsControl.Resources>
</ItemsControl>
The ItemsControl will create a Canvas element and for every GeometricElement in my Elements collection it will add a new child UI element based on the type of object in Elements.
Items controls are bound to collections and can add or remove elements based on what's happening in the collection within your code. It determines the UI element to add by looking for a DataTemplate that is designed for a particular Type. This is a common, and important, pattern and is why using magic strings will hurt you in the long run; the magic string route won't let you leverage the power of the framework already built into WPF.
Now, I'm not saying this will work out of the box. You'll probably run into properties that won't bind without some heavy lifting. You might even have to extend the geometry primitives to get them to behave how you want. But this is the pattern used in WPF applications. Understanding the pattern and using it will help you avoid hours of stress and failure.
I have a Contact entity that exposes a navigation proeprty for child Phone entities.
Public Class Contact : Inherits EntityObject
Public Property Phones() As EntityCollection(Of Phone)
EndClass
I want to Xamly retrieve the first phone of the bound contact.
I tried the following but it doesn't work.
Note: I also tried Phones[0] (I use VB).
<DataTemplate DataType="{x:Type data:Contact}">
<TextBlock Text="{Binding Phones(0)}"/>
</DataTemplate>
Any suggestions (either in VB or C# will be welcommed)?
In this link I found interesting solutions.
I am still opened to hear about new 'Xamly' ideas, that doesn't have to involve converters etc.
TheJeffro's one looks the best, and this is what I am using till further posts.
I have two projects. One is working and the other isn't however the differences between them is nothing that I think "should" be of any importance. The first project is the one that is broken and it is the one I am trying to fix. The second project is a little sample project that I created when the first project just won't work at all. Of course the sample works perfectly.
Here is the view for the first project. I have removed a bunch of the "MainWindowTabControlStyle" because it is just the combo box that is broken. I am reasonable certain that the issue is not in the style because it is a copy and paste from the project that is working.
<Grid>
<TabControl Style="{DynamicResource MainWindowTabControlStyle}">
<TabItem Header="Tab 1"/>
<TabItem Header="Tab 2"/>
</TabControl>
</Grid>
<Style x:Key="MainWindowTabControlStyle" TargetType="{x:Type TabControl}">
...
<ComboBox
HorizontalAlignment="Right"
VerticalAlignment="Top"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Subscriptions, Mode=Default}"
SelectedItem="{Binding Path=SelectedSubscription, Mode=OneWayToSource}"
ItemTemplate="{DynamicResource SubscriptionsItemTemplate}"/>
...
</Style>
<DataTemplate x:Key="SubscriptionsItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DisplayName, Mode=Default}"/>
</StackPanel>
</DataTemplate>
Here is the view model that is set to the DataContext of the MainWindow. The ViewModelBase class is the exact same code that Josh Smith wrote in this months MSDN article.
public sealed class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
}
private ObservableCollection<Subscription> subscriptions;
public ObservableCollection<Subscription> Subscriptions
{
get
{
if (subscriptions == null)
{
subscriptions = new ObservableCollection<Subscription>();
subscriptions.Add(new Subscription() { DisplayName = "ABC" });
subscriptions.Add(new Subscription() { DisplayName = "XYZ" });
subscriptions.Add(new Subscription() { DisplayName = "PDQ" });
}
return subscriptions;
}
set { subscriptions = value; }
}
private Subscription selectedSubscription;
public Subscription SelectedSubscription
{
get { return selectedSubscription; }
set { selectedSubscription = value; }
}
}
When I run the project from the debugger the first think that is called is the getter for the Subscriptions collection. Then the setter is called on the SelectedSubscription (it is null). After that I can change the selected item in the combobox till I am blue in the face and the setter for the SelectedSubscription property doesn't get changed again. It is important to note that the combobox does contain the correct values.
In the second project the code is identical but the first thing that is called is the setter for the SelectedSubscription property (it is null) then the getter for the Subscriptions collection is called and finally the setter for the SelectedSubscription is called a second time and it has a value that matches the first item in the Subscriptions collection.
This little jewel has cost me about 5 hours if you have any ideas at all I am willing to try it.
Thanks
Possibly change
SelectedItem="{Binding Path=SelectedSubscription, Mode=OneWayToSource}"
to
SelectedItem="{Binding Path=SelectedSubscription, Mode=TwoWay}"
Sorry about the delay in getting an answer posted. There was some kind of issue with getting an Open ID up and running.
This is a seriously weird issue.
The resolution to this problem didn't come from the window at all. Prior to the window's show method being called there was another window that was opened as a dialog. In this dialog there was the following resource
<Window.Resources>
<DropShadowBitmapEffect x:Key="DropShadowEffect" Noise="0" Opacity="0.45" ShadowDepth="5" Softness="0.25"/>
</Window.Resources>
It was was being referenced by two textblocks in the same window as a "DynamicResource". After turning off the dialog and making the application start with the windows that was having the problem it was discovered that the issue was being caused by the dialog window. While I was researching the issue a coworker suggest that I turn the DynamicResource into a StaticResource because there was no reason for it to be dynamic.
This change in a dialog window using an resource that was only available within the scope of the dialog window fixed the binding issue described above in the "Main Window". I guess stranger things can happen.
The correct way to debug this is to take the working project and to alternately (modify it to match broken code/confirm it works) until it is either identical to the broken project or it breaks. The point at which it breaks tells you where the problem is. Modifying the broken project is typically a lost cause.
As a secondary point, I'd recommend adding the System.Diagnostics namespace to your XAML. It will make errors show up in the Visual Studio Output window.
xmlns:debug="clr-namespace:System.Diagnostics;assembly=WindowsBase"
As a possibly related point (in that it's not really clear what the problem in the broken project is), you might have a look at this StackOverflow question ("Combobox controling Tabcontrol") that relates to:
WPF,
ComboBoxes,
TabControls, and
binding between them using SelectedIndex.
There isn't yet a solution to this question, but it is a simpler problem.
Lastly, Josh Smith's MSDN code is pretty large. It's hard to figure out what you changed to add your ComboBox without seeing all the code.