Related
I'm currently working on a WPF application that uses a plotting library called Live Charts for WPF. I want to save a PNG of my graph, which is described on their github page Save Plot Example also discussed at this stackoverflow question here. The problem is adding a reference to the windows base assembly.
`
private void SaveToPng(FrameworkElement visual, string filename)
{
var encoder = new PngBitmapEncoder();
EncodeVisual(visual, filename, encoder);
}
private static void EncodeVisual(FrameworkElement visual, string fileName, BitmapEncoder encoder)
{
var bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
//bitmap.Render();
bitmap.Render(visual);
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = File.Create(fileName)) encoder.Save(stream);
}
`
I have tried to add this dll as a reference which is located at C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0, but when I do this it does not work. It is actually implicitly included in the project, so that may be why I can add it explicitly like I did with the PresentationCore.dll and PresentationFramework.dll which were also required and solved a few errors. The error states: the type 'System.Windows.Freezable' is defined in an assembly that is not referenced. You must add a reference to assembly 'WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. This is shown by hovering over the call to bitmap.Render(visual), and when hovering over encoder.Save(stream) as shown in the picture and in the above code. I believe resolving this dependency would fix the problem, but I cannot figure out how. Thank you.
Picture of Project
Discovered what I believe is the answer to the problem. I was creating the SaveToPNG and EncodeVisual methods inside of a class library which would be used in the WPF project. The class library is unable to accept WindowsBase as an explicit reference, but the WPF project itself can. It will take some restructuring of the code to implement this in the WPF project itself, but it seems to be the way to resolve this problem.
I am using .NET 6. Here is the contents of my csproj file in my class library:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<Compile Update="Core Library\Port.cs">
<SubType>Component</SubType>
</Compile>
</ItemGroup>
</Project>
I did not see the attributes that you spoke of, and autocomplete could not reference them in this file. Inside of the IDE (Rider) I was able to target net6.0-windows in the properties menu of the project. I then reinserted the code into the class library, but the same error still occurred. I agree with you that it shouldn't be necessary to reference WindowsBase, which isn't necessary when placing the code in the wpf project itself, but in the class library I also had to reference PresentationCore and PresentationFramework, which did take care of multiple errors.
In my application there is a common Icon.xaml file which contains many PathGeometry Figures having unique key names like as shown below.
<PathGeometry x:Key="CloseGeometry" Figures="m 357.0883 499.0572 12.62375 12.6275 5.31375 -5.31625 -12.62625 -12.62625 12.62625 -12.61875 -5.31375 -5.3125 -12.62375 12.62 -12.6325 -12.62 -5.30375 5.3125 12.6175 12.61875 -12.6175 12.62625 5.30375 5.31625 12.6325 -12.6275 z"/>
<PathGeometry x:Key="NormalGeometry" Figures="M4.3685131,23.127279L4.3685131,47.283243 47.117023,47.283243 47.117023,23.127279z M25.087107,13.948568C23.539013,13.948568 22.286318,15.201555 22.286318,16.74834 22.286318,18.292325 23.539013,19.547214 25.087107,19.547214 26.6327,19.547214 27.886597,18.292325 27.886597,16.74834 27.886597,15.201555 26.6327,13.948568 25.087107,13.948568z M16.126242,13.948568C14.580646,13.948568 13.326751,15.201555 13.326751,16.74834 13.326751,18.292325 14.580646,19.547214 16.126242,19.547214 17.673136,19.547214 18.928329,18.292325 18.928329,16.74834 18.928329,15.201555 17.673136,13.948568 16.126242,13.948568z M7.1679735,13.948568C5.621069,13.948568 4.3685136,15.201555 4.3685131,16.74834 4.3685136,18.292325 5.621069,19.547214 7.1679735,19.547214 8.713438,19.547214 9.9674625,18.292325 9.9674625,16.74834 9.9674625,15.201555 8.713438,13.948568 7.1679735,13.948568z M0,10.684L53.755001,10.684 53.755001,51.668001 0,51.668001z M8.5679998,0L58.668022,0 64,0 64,5.6864691 64,45.317999 58.668022,45.317999 58.668022,5.6864691 8.5679998,5.6864691z"/>
<PathGeometry x:Key="MaximiseGeometry" Figures="M5.2010002,14.812L5.2010002,43.573997 56.098,43.573997 56.098,14.812z M29.868601,3.8869994C28.026201,3.8869996 26.534,5.3791947 26.534,7.2190399 26.534,9.0588851 28.026201,10.553 29.868601,10.553 31.7085,10.553 33.202,9.0588851 33.202,7.2190399 33.202,5.3791947 31.7085,3.8869996 29.868601,3.8869994z M19.200649,3.8869994C17.359457,3.8869996 15.867001,5.3791947 15.867001,7.2190399 15.867001,9.0588851 17.359457,10.553 19.200649,10.553 21.042044,10.553 22.536999,9.0588851 22.536999,7.2190399 22.536999,5.3791947 21.042044,3.8869996 19.200649,3.8869994z M8.5339746,3.8869994C6.6931,3.8869996 5.2010002,5.3791947 5.2010002,7.2190399 5.2010002,9.0588851 6.6931,10.553 8.5339746,10.553 10.37495,10.553 11.867,9.0588851 11.867,7.2190399 11.867,5.3791947 10.37495,3.8869996 8.5339746,3.8869994z M0,0L63.999001,0 63.999001,48.792999 0,48.792999z"/>
<PathGeometry x:Key="MinimiseGeometry" Figures="M 0 1, 1 1 "/>
.....
But my problem is that there are around 300 to 400 different PathGeometries and it becomes difficult to check whether particular type of Image exists or not.
Example:
If new WPF form is gettign developed by programmer in which s\he needs to use delete Icon then s\he will first check in Icon.xaml file whether it already exists or not, if not then it will be added.But this checking needs to be done manually which is a pain.
So is there any simplest way to preview or check whether particular iamge exists or not.
Currently, I konw two tools can help you preview PathGeometry data of xaml.
XamlPadX
Download: XamlPadX v4.0.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<Path Stroke="Black" StrokeThickness="2" Data="M4.3685131,23.127279L4.3685131,47.283243 47.117023,47.283243 47.117023,23.127279z M25.087107,13.948568C23.539013,13.948568 22.286318,15.201555 22.286318,16.74834 22.286318,18.292325 23.539013,19.547214 25.087107,19.547214 26.6327,19.547214 27.886597,18.292325 27.886597,16.74834 27.886597,15.201555 26.6327,13.948568 25.087107,13.948568z M16.126242,13.948568C14.580646,13.948568 13.326751,15.201555 13.326751,16.74834 13.326751,18.292325 14.580646,19.547214 16.126242,19.547214 17.673136,19.547214 18.928329,18.292325 18.928329,16.74834 18.928329,15.201555 17.673136,13.948568 16.126242,13.948568z M7.1679735,13.948568C5.621069,13.948568 4.3685136,15.201555 4.3685131,16.74834 4.3685136,18.292325 5.621069,19.547214 7.1679735,19.547214 8.713438,19.547214 9.9674625,18.292325 9.9674625,16.74834 9.9674625,15.201555 8.713438,13.948568 7.1679735,13.948568z M0,10.684L53.755001,10.684 53.755001,51.668001 0,51.668001z M8.5679998,0L58.668022,0 64,0 64,5.6864691 64,45.317999 58.668022,45.317999 58.668022,5.6864691 8.5679998,5.6864691z" />
</Grid>
</Page>
Then put the PathGeometry data (string of the node "Figures") to the value of inside "Data":
Next, you need to click "Auto Parse" button in left top postion, you can view the rendering result (red border region in screenshot). See below, I just use the data second one from your data.
WPF Geometry Transformation Tool
Download: WPF Geometry Transformation Tool.
Put the string of the node "Figures" into the textarea of Input Geometry, then you can see the result (red border region in screenshot).
In XAML-file of the SquadView page (VfmElitaSilverlightClientView.Pages.SquadView) I am using custom value converter. XAML-file is in "VfmElitaSilverlightClientView" namespace. Separate folder was created for converter and it is in "VfmElitaSilverlightClientView.Converter" namespace (in the same assembly). To use converter following code is used in XAML:
xmlns:Converter="clr-namespace:VfmElitaSilverlightClientView.Converter"
...
<NavigationControls:Page.Resources>
<Converter:BooleanToVisibilityConverter x:Key="resourceBooleanToVisibilityConverter" />
</NavigationControls:Page.Resources>
All works fine. Here I want to move converter class into a custom separate assembly "SilverlightCommonView" and class himself will be in "SilverlightCommonView.Converter" namespace. The XAML code is changed to the following:
xmlns:Converter="clr-namespace:SilverlightCommonView.Converter;assembly=SilverlightCommonView"
...
<NavigationControls:Page.Resources>
<Converter:BooleanToVisibilityConverter x:Key="resourceBooleanToVisibilityConverter" />
</NavigationControls:Page.Resources>
In this case when application throws following exception:
An unhandled exception ('Unhandled
Error in Silverlight Application...
Code: 4004 Category:
ManagedRuntimeError Message:
Microsoft.Practices.Unity.ResolutionFailedException:
Resolution of dependency failed, type="VfmElitaSilverlightClientView.Pages.SquadView",
name="(none)".
Exception occurred while: Calling constructor
VfmElitaSilverlightClientView.Pages.SquadView(). Exception is: XamlParseException -
The type 'BooleanToVisibilityConverter' was not found because
'cl...:SilverlightCommonView.Converter;assembly=SilverlightCommonView'
is an unknown namespace.
It's unclear why specified namespace is unknown (those assembly is referenced by the current one).
Please advise.
Any thoughts are welcome.
I'd bet you do not have an assembly reference to your shared/common project from your application project.
I have a resource defined in my Xaml file as follows:
<Path x:Key="myPath"
Data="M14.773241,18.080208 C12.373256,18.080208 10.239936,19.30687 10.239936,27.573483
L10.239936,36.106766 C10.239936,45.440037 12.586588,46.506699 14.986573,46.506699
C18.613216,46.506699 19.359879,42.400059 19.359879,35.3601 L19.359879,27.733482
C19.359879,20.05353 17.386559,18.080208 14.773241,18.080208 z M14.879907,11.786915
C17.973221,11.786915 22.293194,13.013573 24.906511,17.920212 C26.773167,21.386856
27.519829,27.093487 27.519829,32.213455 C27.519829,34.506775 27.306496,41.706726
24.906511,46.453365 C23.626518,49.013351 20.906536,52.799992 15.199905,52.799992
C2.1333201,52.799992 2.1333201,37.600086 2.1333201,32.160122 C2.1333201,28.05348
2.1333201,22.666847 4.4266391,18.453541 C5.8666301,15.840225 8.639946,11.786915
14.879907,11.786915 z"
/>
I want to able to add multiple "instances" of this path (and several others) to a StackPanel. Of course, I can't simply add "myPath" to the panel since it's already a child of another container.
However, I can't seem to be able to clone the path either. I've tried:
Path clone = new Path()
{
Data = source.Data
};
But no luck...exception about value being out of expected range.
Finally, I tried digging into source.Data (a PathGeometry), but it contains no PathFigures...I have no idea why, since the Path does render if I copy it from the resource section to a panel directly.
What gives?
Thanks,
Sergio
Put the path data in a string resource:
<Page.Resources>
<system:String x:Key="PathData">
M14.773241,18.080208 C12.373256,18.080208 10.239936,19.30687 10.239936,27.573483
L10.239936,36.106766 C10.239936,45.440037 12.586588,46.506699 14.986573,46.506699
C18.613216,46.506699 19.359879,42.400059 19.359879,35.3601 L19.359879,27.733482
C19.359879,20.05353 17.386559,18.080208 14.773241,18.080208 z M14.879907,11.786915
C17.973221,11.786915 22.293194,13.013573 24.906511,17.920212 C26.773167,21.386856
27.519829,27.093487 27.519829,32.213455 C27.519829,34.506775 27.306496,41.706726
24.906511,46.453365 C23.626518,49.013351 20.906536,52.799992 15.199905,52.799992
C2.1333201,52.799992 2.1333201,37.600086 2.1333201,32.160122 C2.1333201,28.05348
2.1333201,22.666847 4.4266391,18.453541 C5.8666301,15.840225 8.639946,11.786915
14.879907,11.786915 z
</system:String>
</Page.Resources>
And to use it:
<Path x:Name="Path1" Data="{StaticResource PathData}" Fill="Blue" ... />
<Path x:Name="Path2" Data="{StaticResource PathData}" Fill="Red" ... />
You'll need this in your XAML declaration:
xmlns:system="clr-namespace:System;assembly=mscorlib"
If you want to create paths programmatically using a common path string, Silverlight is missing a bit of key functionality that WPF has -- so you have to kludge it:
string pathXaml =
#"<Path xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
Data=""path_data_goes_here"" />";
Path path = (Path)System.Windows.Markup.XamlReader.Load(pathXaml);
While trying to answer a question in the vicinity 'Unit Testing WPF Bindings' I had the following niggling question..
What's the best way to find if you have WPF Data Binding wiring setup incorrectly (or you just broke something that was wired up correctly) ?
Although the unit-testing approach seems to be like Joel's 'ripping off your arm to remove a splinter'.. I am looking around for easier less Overhead ways to detect this.
Everyone seems to have committed themselves to data binding in a big way with WPF.. and it does have its merits.
In .NET 3.5 it was introduced a new way to specifically output tracing information about specific data bindings.
This is done through the new System.Diagnostics.PresentationTraceSources.TraceLevel attached property that you can apply to any binding or data provider. Here is an example:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="Debug Binding Sample"
Height="300"
Width="300">
<StackPanel>
<TextBox Name="txtInput" />
<Label>
<Label.Content>
<Binding ElementName="txtInput"
Path="Text"
diag:PresentationTraceSources.TraceLevel="High" />
</Label.Content>
</Label>
</StackPanel>
</Window>
This will put trace information for just that particular binding in Visual Studio's Output Window, without any tracing configuration required.
Best I could find...
How can I debug WPF Bindings? by Beatriz Stollnitz
Since everyone can't always keep one eye on the Output Window looking for Binding errors, I loved Option#2. Which is add this to your App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.Windows.Data" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
</sources>
<switches>
<add name="SourceSwitch" value="All" />
</switches>
<sharedListeners>
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="GraveOfBindErrors.txt" />
</sharedListeners>
<trace autoflush="true" indentsize="4"></trace>
</system.diagnostics>
</configuration>
Pair that up with a good regex scan script to extract out relevant info, that you can run occasionally on the GraveOfBindErrors.txt in your output folder
System.Windows.Data Error: 35 : BindingExpression path error: 'MyProperty' property not found on 'object' ''MyWindow' (Name='')'. BindingExpression:Path=MyProperty; DataItem='MyWindow' (Name=''); target element is 'TextBox' (Name='txtValue2'); target property is 'Text' (type 'String')
I use the solution presented here to turn binding errors into native Exceptions: http://www.jasonbock.net/jb/Default.aspx?blog=entry.0f221e047de740ee90722b248933a28d
However, a normal scenario in WPF bindings is to throw exceptions in case the user input cannot be converted to the target type (for instance, a TextBox bound to a integer field; the input of a non-numeric string results in a FormatException, the input of number that is too large results in an OverflowException). A similar case is when the Setter of the source property throws an exception.
The WPF way of handling this is via ValidatesOnExceptions=true and ValidationExceptionRule to signal the user the supplied input is not correct (using the exception message).
However, these exception are also send to the output window and thus 'caught' by the BindingListener, resulting in an error...clearly not the behaviour you'd want.
Therefore, I expanded the BindingListener class to NOT throw an Exception in these cases:
private static readonly IList<string> m_MessagesToIgnore =
new List<String>()
{
//Windows.Data.Error 7
//Binding transfer from target to source failed because of an exception
//Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
//To cope with these kind of errors
"ConvertBack cannot convert value",
//Windows.Data.Error 8
//Binding transfer from target to source failed because of an exception
//Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
//To cope with these kind of errors
"Cannot save value from target back to source"
};
Modified lines in public override void WriteLine(string message):
....
if (this.InformationPropertyCount == 0)
{
//Only treat message as an exception if it is not to be ignored
if (!m_MessagesToIgnore.Any(
x => this.Message.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
{
PresentationTraceSources.DataBindingSource.Listeners.Remove(this);
throw new BindingException(this.Message,
new BindingExceptionInformation(this.Callstack,
System.DateTime.Parse(this.DateTime),
this.LogicalOperationStack, int.Parse(this.ProcessId),
int.Parse(this.ThreadId), long.Parse(this.Timestamp)));
}
else
{
//Ignore message, reset values
this.IsFirstWrite = true;
this.DetermineInformationPropertyCount();
}
}
}
You can use the trigger debugging feature of WPF Inspector. Just download the tool from codeplex and attach it to your running app. It also shows binding errors on the bottom of the window.
Very useful tool!
Here's a useful technique for debugging/tracing triggers effectively. It allows you to log all trigger actions along with the element being acted upon:
http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html
This was very helpful to us but I wanted to add to those who find this useful that there is a utility that Microsoft provides with the sdk to read this file.
Found here: http://msdn.microsoft.com/en-us/library/ms732023.aspx
To open a trace file
1.Start Service Trace Viewer by using a command window to navigate to your
WCF installation location (C:\Program
Files\Microsoft
SDKs\Windows\v6.0\Bin), and then type
SvcTraceViewer.exe. (although we found ours in \v7.0\Bin)
Note: The Service Trace Viewer tool
can associate with two file types:
.svclog and .stvproj. You can use two
parameters in command line to register
and unregister the file extensions.
/register: register the association of
file extensions ".svclog" and
".stvproj" with SvcTraceViewer.exe
/unregister: unregister the
association of file extensions
".svclog" and ".stvproj" with
SvcTraceViewer.exe
1.When Service Trace Viewer starts, click File and then point to Open.
Navigate to the location where your
trace files are stored.
2.Double-click the trace file that you want to open.
Note: Press SHIFT while clicking
multiple trace files to select and
open them simultaneously. Service
Trace Viewer merges the content of all
files and presents one view. For
example, you can open trace files of
both client and service. This is
useful when you have enabled message
logging and activity propagation in
configuration. In this way, you can
examine message exchange between
client and service. You can also drag
multiple files into the viewer, or use
the Project tab. See the Managing
Project section for more details.
3.To add additional trace files to the collection that is open, click File
and then point to Add. In the window
that opens, navigate to the location
of the trace files and double-click
the file you want to add.
Also, as for the filtering of the log file, we found these this link extremely helpful:
http://msdn.microsoft.com/en-us/library/ms751526.aspx
For anyone like me looking for a pure programmatic way of enabling all WPF Tracing at a given Trace Level, here is a piece of code that does it. For reference, it's based on this article: Trace sources in WPF.
It doesn't requires a change in the app.config file, and it does not require to change the registry either.
This is how I use it, in some startup place (App, etc.):
....
#if DEBUG
WpfUtilities.SetTracing();
#endif
....
And here is the utility code (by default it sends all Warning to the Default Trace Listener):
public static void SetTracing()
{
SetTracing(SourceLevels.Warning, null);
}
public static void SetTracing(SourceLevels levels, TraceListener listener)
{
if (listener == null)
{
listener = new DefaultTraceListener();
}
// enable WPF tracing
PresentationTraceSources.Refresh();
// enable all WPF Trace sources (change this if you only want DataBindingSource)
foreach (PropertyInfo pi in typeof(PresentationTraceSources).GetProperties(BindingFlags.Static | BindingFlags.Public))
{
if (typeof(TraceSource).IsAssignableFrom(pi.PropertyType))
{
TraceSource ts = (TraceSource)pi.GetValue(null, null);
ts.Listeners.Add(listener);
ts.Switch.Level = levels;
}
}
}
My suggestion at 2021:
The Best way is to use Benoit Blanchon small library from Nuget
His original post at here: https://stackoverflow.com/a/19610384/6296708
His GitHub link and more info about how to use it + Nuget command: https://github.com/bblanchon/WpfBindingErrors
Its features (until now!):
throw exception on binding errors (+ line number)
If source Variable throw any exceptions, this library will catch it and show it.
Unit Test supports too!
Happy Coding!