Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts

Sunday, January 31, 2010

Using log4net with .Net 4.0 WPF Applications

I ran into some issues trying to get log4net up and running on my current project, which is being written in VS2010 Beta2, targeting the .net 4.0 framework.  I went about adding a reference to log4net, setup my app.config with a rolling log-file appender and added a call to XmlConfigurator.Configure() in one of my classes.

I then went to compile and got the following error: The type or namespace name 'log4net' could not be found (are you missing a using directive or an assembly reference?) 

I double-checked, and yes, I had indeed added a reference to log4net, so what was wrong?  Turns out, for .net 4.0 WPF projects, the default Target Framework is the “.Net Framework 4 Client Profile”, which is a subset of the full framework with the goal of shrinking footprint of the .net framework needed to download for a typical windows application.  However, log4net apparently needs access to system.web.dll, which isn’t included in the client profile. 

To fix your app so it’ll compile/run, open your project’s properties page, and set the Target Framework to “.Net Framework 4” and save your changes. 

Tuesday, February 10, 2009

Responsive WPF Interfaces

I had a bit of a challenge today while trying to get a WPF ProgressBar to send feedback to my UI while a long-running processes ran. 

My first challenge was finding “that one property that lets the ProgressBar animation run continuously” – IsIndeterminate

My next challenge was setting the IsIndeterminate property to true before firing off my long-running process.   I remembered something about using the Dispatcher, but even using that didn’t reflect the ProgressBar property changes to the UI.  I briefly considered trying an evil DoEvents type trick, but came to my senses before heading down that road.

I landed on creating a delegate which I could invoke to fire off my long-running process, and it ended up looking something like this (forgive the crude method names, this was some spike code I was playing around with:

private delegate void UpdateProgressbarIndeterminateState(bool isEnabled);
private void CompareClick(object sender, RoutedEventArgs e){
Dispatcher.Invoke(DispatcherPriority.Normal,
(UpdateProgressbarIndeterminateState)
delegate(bool isIndeterminate){
progressBar.IsIndeterminate = isIndeterminate;
}, true);

AsyncDelegate caller = PerformCompare;
caller.BeginInvoke(AfterCompareCallback, null);
}

internal delegate void AsyncDelegate();
private static void PerformCompare() {
DataComparer.Execute();
}

protected void AfterCompareCallback(IAsyncResult ar) {
Dispatcher.Invoke(DispatcherPriority.Normal,
(UpdateProgressbarIndeterminateState)
delegate(bool isIndeterminate) {
progressBar.IsIndeterminate = isIndeterminate;
}, false);
}

Tuesday, February 03, 2009

WPF DataGrid Conditional Formatting

I recently ran into a problem on my project where I needed to apply some conditional formatting to WPF DataGrid Cells based upon values from another property in my bound object.

The requirement was pretty simple: if condition is met, change the cell-text color to red, otherwise, leave it black.  What should have been a pretty simple task (never heard a programmer say that, right?) ended up taking me more time than I’d care to admit.

After fumbling around with a few attempts at the IValueConverter and a DataTemplateSelector, I still was not having any luck in getting my conditional formatting to work.  I eventually landed back at my usual source of information for the WPF ToolkitCodePlex, and “shockingly”, the answer was in the discussion for the project.

I had been fighting the “Foreground” property of the DataGridTextColumn directly, trying what was recommended in this article, but I just couldn’t get that working.  Once I followed the CodePlex forum recommendation of embedding a CellStyle into the DataGridTextColumn, things worked as expected.

Friday, January 30, 2009

Two-way Data Binding with WPF DataGrids

We’re making use of the the WPF Toolkit’s DataGrid control in my current project and have solved a few things along the way that weren’t entirely obvious to us at the start. One of these things was figuring out how to automatically reflect domain object changes in the UI.

Of the three developers on this project, Nik Clarkson has the most background with WPF and we usually throw out ideas to him and he “translates” what we want to do to into WPF terms and we’re off and running. In the case of getting our UI to reflect domain model changes, he mentioned BindingMode.

I was able to find some examples that showed how to do this in XAML pretty quickly, but I spent a few cycles trying to get this to work with a DataGridColumn that I was adding programmatically. My first attempt looked like how you’d do it in XAML a-la new Binding("Price, Mode = BindingMode.Two-way”), but that didn’t work.

I decided to make up a fresh batch of coffee in the team french-press, and then it hit me: object initializers. A quick edit and I ended up with following:

var priceColumn = new DataGridTextColumn{ Header = "Price", Width = DataGridLength.Auto,
Binding = new Binding("Price") { Mode = BindingMode.Two-way, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }};
ResultsGrid.Columns.Add(priceColumn);
This worked perfectly with the “Price” property I was binding to, since this was a property on one of our LINQ to SQL objects, and as such was raising the property-changed event for us in the generated code. When I went to do the same thing with another column (one not generated by the LINQ to SQL designer), I wasn’t seeing my edits reflected in my UI, but did see them in the domain objects via the debugger.

I had forgotten to raise the property-changed event in my ProposedPrice setter, so once I changed it to the following, everything worked great.
if (_proposedPrice != value)
{
SendPropertyChanging();
_proposedPrice = value;
SendPropertyChanged("ProposedPrice");
}

Friday, January 16, 2009

AutoScroll panels in WPF

I’m still pretty new to WPF, coming from a WinForms background, and I keep running into situations where stuff that I can do easily in WinForms just isn’t there in WPF. Well, it’s there, I just don’t know how to do it. My latest example was a requirement to add some auto-scrolling to a WrapPanel, and I couldn’t find any sort of “overflow=auto” type setting on the WrapPanel, so off to Google I went.

Turns out WPF provides a pretty simple mechanism for allowing scroll: ScrollViewer. This control allowed me to do exactly what I needed to get done, but it needed to be treated as a container around my WrapPanel - a concept I’m seeing more and more as I get into WPF – another example of this was adding borders to a panel.

Here’s an example of a WrapPanel that has vertical auto-scrolling:

<ScrollViewer Name="MyScroller" VerticalScrollBarVisibility="Auto">
<WrapPanel Name="MyPanel"></WrapPanel>
</ScrollViewer>

Monday, December 22, 2008

WPF DataGrid CheckBox Column Editing

We’re using the WPFToolkit on my current project, specifically the DataGrid control. We needed to programmatically add some CheckBox Columns to the layout, and it was pretty straight-forward.

The only issue we had was the cells required two clicks to flip the checked state of these cells. I spent a few minutes searching through the Discussions for the project and stumbled across this gem: Single Click Editing – worked like a charm (and now QA should be able to resolve the bug that was generated around this quirky functionality).

FileNotFoundException: Could not load file or assembly 'Microsoft.TeamFoundation.Client....

At the start of my current project, I decided it was time to rewrite my TFS Build Utility against the 2008 API/SDK.

I didn’t get get very far before I started to see a “System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.TeamFoundation.Client, Version=9.0.0.0” message whenever I ran my code.

More strange, the app would bring up my main form just fine, but as soon as it hit the constructor of my presenter, I’d get that error. The first line in my constructor was a call to a method where I’d be initializing my TeamFoundationServer object, but I never even got to that line, the exception happened as soon as I stepped into the first line of the constructor.

After a bit of Google searching, I eventually landed on Omar Villarreal's post on using the TFS API in a 64-bit environment – which is what I was doing, and the solution: setting the Platform Target property for my project to x86, instead of “Any CPU” as is set by default in Visual Studio.

Saturday, December 06, 2008

TeamBuild Error Running UnitTests with WPF Objects

I’m just wrapping up sprint 1 of my latest project and as such have been taking care of some infrastructure type tasks. We’re using TFS2008 for our SCM/CI stuff, so I created a new build definition for our main project (WPF/Linq to SQL). We had about a dozen unit tests at this point, all of which we green on our machines (Works on my machine), but once I fired off my build on the CI box, two of the tests failed with the following error:

Test method TestAssembly.TestClass.MyTest threw exception: System.Windows.Markup.XamlParseException: 'StackPanel' object cannot be added to 'Grid'. The program issued a command but the command length is incorrect. (Exception from HRESULT: 0x80070018) Error at object 'System.Windows.Controls.StackPanel' in markup file 'TestApp.UserInterface;component/view/myview.xaml'. ---> System.Runtime.InteropServices.COMException: The program issued a command but the command length is incorrect. (Exception from HRESULT: 0x80070018).

The two tests that failed happened to be the two that created an instance of a WPF Window, which no other tests in the suite did, so at least we had some clues to Google with. It didn’t take long to stumble across this page: MS Forums: .NET 3.5 SP1 breaks use of WPF under IIS.

Although we weren’t doing anything with IIS, the rest of the symptoms sounded exactly like what we were dealing with. We took the advice given in the first community comment that indicated we should run the executable in XP SP2 compatibility mode and applied that the the TFSBuildService executable. The next build succeeded and we were back to coding.

The good news is that MS intends to fix this issue with a future patch/service pack, but not until sometime next year, so for now, you’re stuck with forcing compatibility mode on your failing executables.

Thursday, December 04, 2008

Mocking the Unity Container

While trying to get some tests running for my current project (WPF, VS2008, C#, MSTest, RhinoMocks 3.5, Vista 64bit), I ran into an issue where I can’t mock out the Unity Container.

I was following the advice on Randy's Blog, but when I hit the line where I’m creating a stub of the IUnityContainer, the test blows up with the error below, and like others have mentioned, when in debug, the error doesn’t surface. Here’s the error I’m seeing:

Initialization method Test.Presenter.GivenPresenter.TestAnythingAndSeeItFail threw exception. System.BadImageFormatException: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B).

Seems I’m not the only one running into this error:

http://www.nabble.com/BadImageFormatException,-but-not-when-debugging-td18742529.html

http://groups.google.com/group/RhinoMocks/browse_thread/thread/b2235a13f920c616

Edit:

After a failed attempt to created a fake based on IUnityContainer, I ran across Roy Osherove’s post on creating an AutoMockingUnityContainer which worked perfectly for my test needs.