The trick is not use use a TextBlock as conventional wisdom would indicate, but to use a FlowDocument to achieve this kind of layout.
For future reference (I am going to need something like this fairly soon), try the following XAML snippet and the resulting WPF app screenshot to demonstrate how to display a button in the top right hand corner with text wrapped around it. In my real-world apps I am using the MVVM pattern with all sorts of bindings and events etc, but this should hopefully enable me to get there:
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
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"
Title="MainWindow" Height="300" Width="400">
<Grid>
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph>
<Floater Width="125"
HorizontalAlignment="right" Margin="0,0,0,0" >
<BlockUIContainer>
<Button
Content="Go!"
Height="90" Width="100" />
</BlockUIContainer>
</Floater>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Suspendisse et diam felis. Vestibulum ac nisl mi.
Etiam varius velit lobortis nibh vestibulum nec consequat velit pellentesque.
Cras commodo libero placerat nulla dapibus eget porttitor ligula tempor.
Donec nisl massa, congue et pretium sit amet, feugiat vel est.
Nulla dapibus metus in justo pulvinar sit amet viverra lorem rhoncus.
Integer placerat interdum massa et mattis.
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</Grid>
</Window>
Which when run gives the following output:
Another example, this time using RichTextBox:
MainWindow.xaml
<Window x:Class="WrapText.MainWindow"
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:WrapText"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="320">
<Grid>
<RichTextBox Margin="-3,-3,-3,-3" >
<FlowDocument>
<Paragraph>
<Floater
Margin="0,0,0,0"
Padding="3"
Width="60"
HorizontalAlignment="Right">
<BlockUIContainer
Margin="0,0,0,0">
<Button
Width="50"
Height="50"
Content="Hello" />
</BlockUIContainer>
</Floater>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vivamus eu urna ipsum. Nullam vulputate quam dolor, eget porttitor
ex sagittis vitae. Nunc auctor purus tellus, ut ultricies dolor
imperdiet a. In scelerisque lacus et ex tempus, quis elementum lacus
bibendum. Etiam lobortis dictum mauris. Sed elementum ornare libero,
et consectetur sapien posuere vitae. Interdum et malesuada fames ac
ante ipsum primis in faucibus. Praesent nec tortor sit amet dui
varius consectetur.
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</Window>
Notable quote: “First of all DataGridTextColumn or any other supported dataGrid columns doesn’t lie in Visual tree of DataGrid. Hence, by default it doesn’t inherit DataContext of DataGrid. But, it works for Binding DP only and for not other DP’s on DataGridColumn.”
Here is an example of how to achieve this in a Visual Studio WPF application.
Step 1: Create a Visual Studio WPF application:
Step 2: Create a Freezable class
“Freezable objects can inherit the DataContext even when they’re not in the visual or logical tree. So, we can take advantage of that to our use. First create class inheriting from Freezable and Data DP which we can use to bind in XAML”.
BindingProxy.cs
using System.Windows;
namespace DataGridColumnVisibility
{
public class BindingProxy : Freezable
{
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register(&amp;amp;amp;quot;Data&amp;amp;amp;quot;, typeof(object),
typeof(BindingProxy));
public object Data
{
get { return GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
}
}
Step 3: Set the styles and converters needed in the App.xaml file
A short post demonstrating how to use expander controls in WPF, to create a list of collapsible / expandable menu items in your C# WPF application
Create a new Visual Studio application
Create a View Model class for your main window
MainWindowViewModel.cs
using System.Collections.Generic;
namespace ExpanderExample
{
public class ApplicationListItem
{
public ApplicationListItem(string name, string openButtonText, string updateButtonText,
bool updateButtonVisibility = false, bool progressVisibility = true)
{
Name = name;
OpenButtonText = openButtonText;
UpdateButtonText = updateButtonText;
UpdateButtonVisibility = updateButtonVisibility;
ProgressVisibility = progressVisibility;
}
public string Name { get; set; }
public string OpenButtonText { get; set; }
public string UpdateButtonText { get; set; }
public bool UpdateButtonVisibility { get; set; }
public bool ProgressVisibility { get; set; }
}
public class ListItem
{
public ListItem(string title)
{
Title = title;
}
public string Title { get; set; }
public List<ApplicationListItem> ListItems { get; set; } = new List<ApplicationListItem>();
public void AddListItem(ApplicationListItem listItem)
{
ListItems.Add(listItem);
}
}
public class MainWindowViewModel
{
public MainWindowViewModel()
{
var listItem1 = new ListItem("CMM");
var appListItem1 = new ApplicationListItem("CMM - Local (English)", "Open", "Update", false, false);
var appListItem2 = new ApplicationListItem("CMM - Local (German)", "Open", "Update", false, false);
var appListItem3 = new ApplicationListItem("CMM - Local (Japanese)", "Open", "Update", true);
listItem1.AddListItem(appListItem1);
listItem1.AddListItem(appListItem2);
listItem1.AddListItem(appListItem3);
Items.Add(listItem1);
var listItem2 = new ListItem("Sales Aid");
var appListItem4 = new ApplicationListItem("Sales Aid - Local (English)", "Open", "Update", true, false);
listItem2.AddListItem(appListItem4);
Items.Add(listItem2);
}
public List<ListItem> Items { get; } = new List<ListItem>();
}
}
So that we may hide/collapse/make visible individual controls in our expandable items list, set the boolean to visibility conversion in app.xaml
On building and running the application see that the window contains the two expander controls as shown:
On expanding the expander controls see that thse now contain the ItemsControl elements (buttons, title strings, progress bars etc), which are visible according to the values set during the initialisation of the main window View Model class.
This post demonstrates how to apply the 2-opt algorithm to a number of standard test problems in C# while displaying the
results in a WPF style window, while using the MVVM design pattern.
See this link for an overview of the two opt algorithm.
But essentially the 2-opt link swapping heuristic can be summarised by the following steps:
The actual 2-opt heuristic can be summarised by the following pseudocode steps, repeating for all feasible combinations of I and k:
1. take route[1] to route[i-1] and add them in order to new_route
2. take route[i] to route[k] and add them in reverse order to new_route
3. take route[k+1] to end and add them in order to new_route
4. return the new_route;
Architecture
This application is designed around the Model View ViewModel architecture (MVVM). I find that MVVM allows for a nice clean separation between the graphical
display, the business logic and data handling.
As with the Java and C++ versions, the user interface is a simple window with buttons for opening the test problem (*.tsp file) and a run button to execute the algorithm(which causes the
display to get updated and re-draw the tour links each time a better tour is found)
Building the User Interface in XAML
I use standard WPF / XAML for the user interface components and the canvas in which to draw the city nodes, tour links etc:
This class I use for handling the business logic and the responding to the button press events from the main user interface.
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Windows.Input;
namespace TwoOpt
{
public class MainWindowViewModel : BaseViewModel
{
private readonly Model _model;
private ICommand _openCommand;
private ICommand _runCommand;
public MainWindowViewModel()
{
_model = new Model();
_model.TourUpdated += ModelOnTourUpdated;
}
public IMainWindow MainWindow { get; set; }
public string Title
{
get { return _model.Title; }
set
{
_model.Title = value;
OnPropertyChanged("Title");
}
}
public ICommand OpenCommand
{
get
{
return _openCommand ?? (_openCommand = new RelayCommand(
x =>
{
var openFileDialog1 = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = @"txt files (*.tsp)|*.tsp|All files (*.*)|*.*",
FilterIndex = 2,
RestoreDirectory = true
};
if (openFileDialog1.ShowDialog() != DialogResult.OK) return;
try
{
Stream stream;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if ((stream = openFileDialog1.OpenFile()) == null) return;
var height = MainWindow.GridHeight();
var width = MainWindow.GridWidth();
_model.CancelJobs();
_model.InitMatrix(stream, height, width);
Title = _model.Title;
DisplayNodes();
MainWindow.UpdateIteration(0, 0, null);
}
catch (Exception ex)
{
MessageBox.Show(@"Error: Could not read file from disk. Original error: " + ex.Message);
}
}));
}
}
public ICommand RunCommand
{
get
{
return _runCommand ?? (_runCommand = new RelayCommand(
x => { _model.Run(); }));
}
}
public List<Pair> Lines => _model.TourCoords;
private void ModelOnTourUpdated(object sender, EventArgs<Tuple<double, int>> eventArgs)
{
var iter = eventArgs.Value.Item2;
var best = eventArgs.Value.Item1;
Update(best, iter);
}
public IEnumerable<string> ReadLines(Func<Stream> streamProvider,
Encoding encoding)
{
using (var stream = streamProvider())
{
using (var reader = new StreamReader(stream, encoding))
{
string line;
while ((line = reader.ReadLine()) != null)
yield return line;
}
}
}
private void DisplayNodes()
{
MainWindow?.PlotNodes(_model.DisplayCoords);
}
private void Update(double best, int iter)
{
MainWindow.UpdateIteration(best, iter, _model.TourCoords);
}
}
}
Within this code I also make use of the Supervisor Controlling Pattern as means of accessing the View controls from within the ViewModel class.
It does this by allowing MainWindow.xaml.cs to inherits from the IMainWindow interface, which provide the functions to plot the nodes and draw the links:
IMainWindow.cs
using System.Collections.Generic;
namespace TwoOpt
{
public interface IMainWindow
{
void UpdateIteration(double best, int iter, List<Pair> tourCoords);
void PlotNodes(List<Pair> displayCoords);
double GridHeight();
double GridWidth();
}
}
MainWindow.xaml.cs
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace TwoOpt
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : IMainWindow
{
public MainWindow()
{
InitializeComponent();
var mainWindowViewModel = DataContext as MainWindowViewModel;
if (mainWindowViewModel != null)
mainWindowViewModel.MainWindow = this;
}
public void PlotNodes(List<Pair> displayCoords)
{
CanvasGrid.Children.Clear();
InvalidateVisual();
foreach (var coord in displayCoords)
{
var ellipse = new Ellipse
{
Width = 4,
Height = 4,
Fill = Brushes.Blue
};
Canvas.SetLeft(ellipse, coord.X());
Canvas.SetTop(ellipse, coord.Y());
CanvasGrid.Children.Add(ellipse);
}
}
public double GridHeight()
{
return DisplayGrid.ActualHeight;
}
public double GridWidth()
{
return DisplayGrid.ActualWidth;
}
public void UpdateIteration(double best, int iter, List<Pair> tourCoords)
{
Dispatcher.Invoke(() =>
{
IterationLabel.Content = "Iteration: " + iter;
BestLabel.Content = "Best distance: " + (int)best;
if (tourCoords == null) return;
var size = tourCoords.Count;
var startCoord = tourCoords[0];
CanvasGrid.Children.Clear();
for (var i = 1; i < size; ++i)
{
var endCoord = tourCoords[i];
var link = new Line
{
X1 = startCoord.X() + 2,
Y1 = startCoord.Y() + 2,
X2 = endCoord.X() + 2,
Y2 = endCoord.Y() + 2,
Stroke = Brushes.Blue
};
CanvasGrid.Children.Add(link);
startCoord = tourCoords[i];
}
var finalLink = new Line
{
X1 = tourCoords[0].X() + 2,
Y1 = tourCoords[0].Y() + 2,
X2 = tourCoords[size - 1].X() + 2,
Y2 = tourCoords[size - 1].Y() + 2,
Stroke = Brushes.Blue
};
CanvasGrid.Children.Add(finalLink);
});
}
}
}
C# implementation of the 2-opt algorithm
// Do all 2-opt combinations
private void TwoOpt()
{
// Get tour size
var size = _tour.TourSize();
//CHECK THIS!!
for (var i = 0; i < size; i++)
{
_newTour.SetCity(i, _tour.GetCity(i));
}
// repeat until no improvement is made
var improve = 0;
var iteration = 0;
while (improve < 500)
{
var bestDistance = _tour.TourDistance();
for (var i = 1; i < size - 1; i++)
{
for (var k = i + 1; k < size; k++)
{
TwoOptSwap(i, k);
iteration++;
var newDistance = _newTour.TourDistance();
if (!(newDistance < bestDistance)) continue;
// Improvement found so reset
improve = 0;
for (var j = 0; j < size; j++)
{
_tour.SetCity(j, _newTour.GetCity(j));
}
bestDistance = newDistance;
// Update the display
SetTourCoords();
TourUpdated.Raise(this, new Tuple<double, int>( bestDistance, iteration));
}
}
improve++;
}
}
And this is how the swap is done:
private void TwoOptSwap(int i, int k)
{
var size = _tour.TourSize();
// 1. take route[0] to route[i-1] and add them in order to new_route
for (var c = 0; c <= i - 1; ++c)
{
_newTour.SetCity(c, _tour.GetCity(c));
}
// 2. take route[i] to route[k] and add them in reverse order to new_route
var dec = 0;
for (var c = i; c <= k; ++c)
{
_newTour.SetCity(c, _tour.GetCity(k - dec));
dec++;
}
// 3. take route[k+1] to end and add them in order to new_route
for (var c = k + 1; c < size; ++c)
{
_newTour.SetCity(c, _tour.GetCity(c));
}
}
Trying out the program
Att48.tsp
I tend to always start out on a reasonably small test problem such as att48.tsp, available from here:
The Model class we use to define our Directory ‘Item’ structure.
In this instance I’m keeping things really simple, just a ‘Name’ and a List of other ‘DirectoryItem’ objects.
Also contained in this class is a recursive function to traverse the ‘DirectoryItem’ node elements:
Model.cs
using System.Collections.Generic;
namespace WpfTreeViewBinding.Model
{
public class Item
{
public string Name { get; set; }
}
public class DirectoryItem : Item
{
public DirectoryItem()
{
Items = new List<DirectoryItem>();
}
public List<DirectoryItem> Items { get; set; }
public void AddDirItem(DirectoryItem directoryItem)
{
Items.Add(directoryItem);
}
public List<Item> Traverse(DirectoryItem it)
{
var items = new List<Item>();
foreach (var itm in it.Items)
{
Traverse(itm);
items.Add(itm);
}
return items;
}
}
}
Step 3: Create the ‘Item Provider’ class
I use this class to knock up an example hierarchical structure of ‘DirectoryItem’ elements and a public property to return this:
ItemProvider.cs
using System.Collections.Generic;
using WpfTreeViewBinding.Model;
namespace WpfTreeViewBinding
{
public class ItemProvider
{
private readonly DirectoryItem _rootDirectoryItem;
public ItemProvider()
{
_rootDirectoryItem = new DirectoryItem {Name = "X"};
var childItem1 = new DirectoryItem {Name = "A"};
var grandChildItem11 = new DirectoryItem {Name = "A1"};
var grandChildItem12 = new DirectoryItem {Name = "A2"};
var greatgrandChildItem2 = new DirectoryItem {Name = "A2_1"};
grandChildItem11.AddDirItem(greatgrandChildItem2);
childItem1.AddDirItem(grandChildItem11);
childItem1.AddDirItem(grandChildItem12);
var childItem2 = new DirectoryItem {Name = "B"};
var childItem3 = new DirectoryItem {Name = "C"};
var childItem4 = new DirectoryItem {Name = "D"};
var grandChildItem121 = new DirectoryItem {Name = "B1"};
childItem2.AddDirItem(grandChildItem121);
var childList1 = new List<DirectoryItem>
{
childItem1,
childItem2,
childItem3,
childItem4
};
_rootDirectoryItem.Items = childList1;
}
public List<Item> DirItems => _rootDirectoryItem.Traverse(_rootDirectoryItem);
}
}
Step 4: Create a ViewModel class
This class we use to bind to the XAML elements that we will define shortly.
It contains the binding property ‘DirItems’ which we create using the ‘ItemProvider’ class defined previously.
ViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using WpfTreeViewBinding.Model;
namespace WpfTreeViewBinding
{
public class ViewModel : INotifyPropertyChanged
{
private List<Item> _dirItems;
public ViewModel()
{
var itemProvider = new ItemProvider();
DirItems = itemProvider.DirItems;
}
public List<Item> DirItems
{
get { return _dirItems; }
set
{
_dirItems = value;
OnPropertyChanged(nameof(DirItems));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected void OnPropertyChanged(string propertyName)
{
VerifyPropertyName(propertyName);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void OnPropertyChanged(int propertyValue)
{
VerifyPropertyName(propertyValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyValue.ToString()));
}
[Conditional("DEBUG")]
private void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
throw new ArgumentNullException(GetType().Name + " does not contain property: " + propertyName);
}
[Conditional("DEBUG")]
private void VerifyPropertyName(int propertyValue)
{
if (TypeDescriptor.GetProperties(this)[propertyValue] == null)
throw new ArgumentNullException(GetType().Name + " does not contain property: " + propertyValue.ToString());
}
}
}
Step 5: Define the Main Window xaml.
This xaml we will update to implement the TreeView and HierarchicalDataTemplate elements needed to display the hierarchical tree structure:
Some practical instructions on how to include resource files to your Visual Studio C# WPF project that are not source code.
Such non-code files can include binary data, text files, media files, string values, icons, XML, or any other type of data.
Project resource data is stored in XML format in the .resx file (named Resources.resx by default).
In this example we demonstrate how resource files can be defined in and accessed from a separate class library, thereby helping to make your project cleaner and less cluttered.
Step 1: Create a new Visual Studio WPF project.
Create a new WPF application for this example:
Step 2: Add a new class library project
Right-click on your solution folder and select Add > New Project. Create a new Class Library application. We’ll call it FileStore:
This project we will use to contain our resource files.
Step 3: Create a folder to store the resource files
In the ‘FileStore’ Class Library project you created, right-click the project folder and select Add > New Folder. Let’s call it ‘Resources’:
Resource files folder
And then add the resource file(s) you would like the executable to be able to access. In this example, I am interested in using an icon resource file. The example icon resource file you can obtain from here:
Copy this file to a Resources folder that would have been created in Step 3.
And in Visual Studio, right-click the Resources folder and select Add > Existing Item. Add the ‘icon.ico’ resource contained in the Resources folder:
(In this Class Library project you can also delete the ‘Class1.cs’ file that gets automatically generated).
Step 4: Create a new resx file
In the ‘FileStore’ Class Library project, right-click the project folder and select Add > New Item.
Select a new Resource file. I prefer to rename this to ‘Resource.resx’:
Step 5: Add the file resource to the resx file.
Double click (select) Resource.resx.
Select Add Resource > Add Existing File.
Select the ‘icon.ico’ that you placed in the Resources folder.
Make sure that the Access Modify is set to ‘Public’ nor ‘Internal’
Resource.resx now looks like this:
Icon resource file
Step 6: Add the ‘FileStore’ dll reference to the main startup project
Right-click on the ‘FileStore’ Class Library project and select rebuild.
Right-click the ‘ResourceFiles’ main startup project and select Add > Reference. In the reference Manager dialog that appears, select the ‘Project’ section and select the ‘FileStore’ project:
Step 7: Add other necessary references to the main startup project
Firstly in order to use the ‘NotifyIcon’ class we need to import the ‘System.Windows.Forms’ using directive.
In the ResourceFiles project, right-click on References and select Add Reference. Search for and select ‘System.Windows.Forms’:
In the same project, we also need to add a reference to System.Drawing:
Step 8: Access the resource in your code
In the MainWindow.xaml.cs code, update so that we can access the icon resource created in the ‘FileStore’ project.
This small code modification will enable the icon resource file to be displayed in the notification area of your Windows screen. Access to the icon file resource is made via the line:
FileStore.Resource.icon;
Full code listing:
using System.Windows;
using System.Windows.Forms;
namespace ResourceFiles
{
public partial class MainWindow : Window
{
NotifyIcon notifyIcon = new NotifyIcon();
public MainWindow()
{
InitializeComponent();
notifyIcon.Icon = FileStore.Resource.icon;
notifyIcon.Visible = true;
notifyIcon.Text = "Check for updates";
}
}
}
Rebuild the whole solution and run.
Notice that the icon resource is displayed in the notification area of the Windows toolbar as shown:
Example scenario: User clicks the mouse in a WPF application – how do we ‘listen’ to that event in order to trigger and handle an event in the main code? A possible solution is to use in WPF MVVM.
See this post to learn how to do this using MvvmLight:
If you need to migrate from an older version, then do these steps:
1. Remove reference to “Microsoft.Expression.Interactions” and “System.Windows.Interactivity”
2. Install the Microsoft.Xaml.Behaviors.Wpf NuGet package.
3. XAML files – replace the xmlns namespaces http://schemas.microsoft.com/expression/2010/interactivity and http://schemas.microsoft.com/expression/2010/interactions with http://schemas.microsoft.com/xaml/behaviors
4. C# files – replace the usings in c# files “Microsoft.Xaml.Interactivity” and “Microsoft.Xaml.Interactions” with “Microsoft.Xaml.Behaviors”
[Older version]
Right click the project folder and select ‘Add Reference’. Select System.Windows.Interactivity reference:
Add the following classes to you project: EventArgs.cs, EventRaiser.cs, RelayCommand.cs
EventArgs.cs
using System;
namespace Interactivity
{
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
Value = value;
}
public T Value { get; private set; }
}
}
EventRaiser.cs
using System;
namespace Interactivity
{
public static class EventRaiser
{
public static void Raise(this EventHandler handler, object sender)
{
if (handler != null)
{
handler(sender, EventArgs.Empty);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
{
if (handler != null)
{
handler(sender, new EventArgs<T>(value));
}
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T value) where T : EventArgs
{
if (handler != null)
{
handler(sender, value);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value)
{
if (handler != null)
{
handler(sender, value);
}
}
}
}
RelayCommand.cs
using System;
using System.Windows.Input;
namespace Interactivity
{
public class RelayCommand<T> : ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
// Ensures WPF commanding infrastructure asks all RelayCommand objects whether their
// associated views should be enabled whenever a command is invoked
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
CanExecuteChangedInternal -= value;
}
}
private event EventHandler CanExecuteChangedInternal;
public void RaiseCanExecuteChanged()
{
CanExecuteChangedInternal.Raise(this);
}
}
}
Step 4: Set the MainWindow.xaml DataContext and Event Triggers
Step 5: Create a ViewModel class for the Main Window
Add the class MainWindowViewModel.cs to your project.
Our MainWindowViewModel class will be used to bind the ‘left mouse button down’ EventName command defined in the MainWindow.xaml.
MainWindowViewModel.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace Interactivity
{
public class MainWindowViewModel
{
private ICommand _leftButtonDownCommand;
public ICommand LeftMouseButtonDown
{
get
{
return _leftButtonDownCommand ?? (_leftButtonDownCommand = new RelayCommand(
x =>
{
DoStuff();
}));
}
}
private static void DoStuff()
{
MessageBox.Show("Responding to left mouse button click event...");
}
}
}
So that when we run the empty WPF application and left click anywhere on the window, the event gets handled, as evidenced by the message box that gets invoked:
Some instruction on how to embed a PowerPoint presentation within a WPF application by converting the file to a XPS format and displaying this using DocumentViewer.
Step 1: Create a WPF Application
Step 2. Include the necessary references
Microsoft.Office.Interop.PowerPoint
Office
ReachFramework
Step 3: Insert DocumentViewer control into MainWindow.xaml
Some instructions on how to use the Mediator design pattern as a means of allowing communication between ViewModel classes in your MVVM / WPF application.
In this example I use the Mediator as a means of communicating to the main window which view to display when the user clicks a button on either of the child views, View1 and View2.
Step 1: Create a new WPF application
Step 2: Add event handling classes
EventArgs.cs
using System;
namespace MvvmSwitchViews
{
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
Value = value;
}
public T Value { get; private set; }
}
}
EventRaiser.cs
using System;
namespace MvvmSwitchViews
{
public static class EventRaiser
{
public static void Raise(this EventHandler handler, object sender)
{
if (handler != null)
{
handler(sender, EventArgs.Empty);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
{
if (handler != null)
{
handler(sender, new EventArgs<T>(value));
}
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T value) where T : EventArgs
{
if (handler != null)
{
handler(sender, value);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value)
{
if (handler != null)
{
handler(sender, value);
}
}
}
}
RelayCommand.cs
using System;
using System.Windows.Input;
namespace MvvmSwitchViews
{
public class RelayCommand<T> : ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
// Ensures WPF commanding infrastructure asks all RelayCommand objects whether their
// associated views should be enabled whenever a command is invoked
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
CanExecuteChangedInternal -= value;
}
}
private event EventHandler CanExecuteChangedInternal;
public void RaiseCanExecuteChanged()
{
CanExecuteChangedInternal.Raise(this);
}
}
}
Step 3: Create the views
For demonstration purposes we add 2 x new views, each with a button that directs the user to another screen:
using System.ComponentModel;
namespace MvvmSwitchViews
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
View1ViewModel1.cs
using System;
using System.Windows.Input;
namespace MvvmSwitchViews
{
public class View1ViewModel : ViewModelBase
{
private ICommand _gotoView2Command;
public ICommand GotoView2Command
{
get
{
return _gotoView2Command ?? (_gotoView2Command = new RelayCommand(
x =>
{
Mediator.NotifyColleagues("ChangeView", false);
}));
}
}
}
}
View2ViewModel.cs
using System;
using System.Windows.Input;
namespace MvvmSwitchViews
{
public class View2ViewModel : ViewModelBase
{
private ICommand _gotoView1Command;
public ICommand GotoView1Command
{
get
{
return _gotoView1Command ?? (_gotoView1Command = new RelayCommand(
x =>
{
Mediator.NotifyColleagues("ChangeView", true);
}));
}
}
}
}
Update the ViewModel class for the Main Window ViewModel as well:
MainWindowViewModel.cs
using System.Windows.Input;
namespace MvvmSwitchViews
{
public class MainWindowViewModel : ViewModelBase
{
private object _view1 = new View1();
private object _view2 = new View2();
private object _currentView;
public MainWindowViewModel()
{
_currentView = _view1;
Mediator.Register("ChangeView", OnChangeView);
}
public object CurrentView
{
get
{
return _currentView;
}
set
{
_currentView = value;
OnPropertyChanged("CurrentView");
}
}
public void OnChangeView(object show)
{
bool showView1 = (bool)show;
CurrentView = showView1 ? _view1 : _view2;
}
}
}
Step 5: Create the Mediator static class
Mediator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MvvmSwitchViews
{
static public class Mediator
{
static IDictionary<string, List<Action<object>>> pl_dict = new Dictionary<string, List<Action<object>>>();
static public void Register(string token, Action<object> callback)
{
if (!pl_dict.ContainsKey(token))
{
var list = new List<Action<object>>();
list.Add(callback);
pl_dict.Add(token, list);
}
else
{
bool found = false;
foreach (var item in pl_dict[token])
if (item.Method.ToString() == callback.Method.ToString())
found = true;
if (!found)
pl_dict[token].Add(callback);
}
}
static public void Unregister(string token, Action<object> callback)
{
if (pl_dict.ContainsKey(token))
pl_dict[token].Remove(callback);
}
static public void NotifyColleagues(string token, object args)
{
if (pl_dict.ContainsKey(token))
foreach (var callback in pl_dict[token])
callback(args);
}
}
}
Step 6: Try the code
So in this example, the MainWindowViewModel class subscribes to the “ChangeView” events that are initiated in the View1ViewModel and View2ViewModel classes that are bound to View1 and View2 respectively.
So when the user clicks the button in the first view, the Mediator class notifies it’s listeners that this event has happened, telling it not to switch to View1 but to View2 instead:
When the dialog appears, select the Browse button. Navigate to the ‘packages’ folder that NuGet has installed to your Visual Studio project. For this project I’m choosing the x86 versions…
Add CefSharp.Wpf.dll:
Add the CefSharp.dll, CefSharp.Core.dll, CefSharp.BrowserSubprocessCore.dll:
If you get the error similar to the following:
Error 1 CefSharp.Common will work out of the box if you specify platform (x86 / x64). For AnyCPU Support see https://github.com/cefsharp/CefSharp/issues/1714 CefSharpBrowser
… make sure you have set the Configuration Manager is set to either x86 or x64 – NOT ‘Any CPU’ otherwise it will never work.
Step 4: Update the MainWindow.xaml to embed the ChromiumWebBrowser control:
Namely, a reference to the CefSharp.Wpf namespace and the ChromiumBrowserControl itself.
The re-build your project. You may have to close and re-open your MainWindow.xaml file to get it to update and display correctly. When run the browser control appears embedded in the WPF application and navigates to the web address pointed to by the ChromiumWebBrowser ‘Address’ property, as shown:
Known issues
The most recent version of CefSharp (version 53.0.0) does not seem to browse PDF documents so well. If this is an issue for you, uninstall this version (by using the NuGet package manager) and install an earlier version instead:
The application will then successfully browse PDF files as shown:
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.