WPF Gotchas?

109 views
Skip to first unread message

Jason Batchkoff

unread,
Nov 24, 2014, 8:58:11 PM11/24/14
to authoring-to...@googlegroups.com
Just curious, are there any gotchas working with WPF in ATF?

I'm exploring that area and if anyone knows anything I'd appreciate some general guidance.  :)

Jason Batchkoff

unread,
Nov 24, 2014, 9:08:38 PM11/24/14
to authoring-to...@googlegroups.com
Quick point, you can use [CallerMemberName] to make the RaisePropertyChanged function much nicer.

void RaisePropertyChanged([CallerMemberNamestring propertyName = null)
{
	var handler = PropertyChanged;
	if (handler != null)
	{
		handler(thisnew PropertyChangedEventArgs(propertyName));
	}
}

This is a .NET 4.5 feature I think?

Anyway, the setters then can look like this:

public Event Event
{
     set 
     { 
        m_event = value;
        RaisePropertyChanged();
     }
}

Ron2

unread,
Nov 24, 2014, 9:46:21 PM11/24/14
to authoring-to...@googlegroups.com
Hi Jason,

I'll let others give specific tips about WPF and ATF. I can say that WPF support is important to us and we're trying to bring it up to par with our WinForms support. It's been a gradual process since we and our clients started out with WinForms and WPF support came later. We're working on a greatly improved WPF-based sample app for our next release (ATF 3.9), at the end of January.

Thanks for the tip about the CallerMemberName attribute. I've added that to our list of improvements we can make when we eventually start using .NET Framework 4.5 / C# 5 features. Currently, we have to support Visual Studio 2010. If there are compelling features that are easy to test, we could use #ifdefs (like we did for extension methods back when we had to support VS2008), but we haven't discussed doing that yet.

.NET Framework 4.5 / C# 5 possible improvements (requires VS2012):

  • Use async and await to improve performance by allowing more hardware threads to be used.
  • Do a test of SetProfileRoot() and StartProfile(), to see if start-up times of big apps can be improved.
  • DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture can save code and problems when creating new threads. http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx
  • Use PureAttribute to “Indicate that a type or method is pure, that is, it does not make any visible state changes.”
  • WPF: support CallerMemberNameAttribute to make WPF event raising a little simpler. See this forum post.
--Ron

julianneh

unread,
Nov 24, 2014, 10:11:28 PM11/24/14
to authoring-to...@googlegroups.com

Hi Jason,

I'm Julianne Harrington, and I'm the ATF team's WPF developer. I'm not aware of any gotchas with using WPF with ATF. As Ron said, our WPF support is a work in progress, but if you're an experienced WPF developer it should all look pretty familiar. I know the existing WPF sample app is woefully inadequate, but it does provide at least a basic starting point, and a more useful one is coming soon. In the meantime, please feel free to get in touch if you have questions as you dive in and I'll be happy to help get you on the right track!

- Julianne



On Monday, November 24, 2014 5:58:11 PM UTC-8, Jason Batchkoff wrote:

Jason Batchkoff

unread,
Dec 1, 2014, 3:26:35 PM12/1/14
to
Hey, thanks for the replies.  Sorry for not getting back sooner.

Context: I'm a WPF programmer with 2 years experience, new to ATF and WinForms.

General questions:

* How do the schema-generated objects compare to DependencyObjects?  They seem pretty similar at first glance, except that schema objects are code-genned, and DepObjs need to be handwritten.

* How do WPF commands compare to ATF's command library?  How does this affect things like ContextMenus?

* Do you have a good sample for blending WinForms and WPF?

* Is it possible to see the new WPF sample app before January?

Jason Batchkoff

unread,
Dec 3, 2014, 8:33:36 PM12/3/14
to authoring-to...@googlegroups.com
Bump?

On Monday, December 1, 2014 12:26:35 PM UTC-8, Jason Batchkoff wrote:
Hey, thanks for the replies.  Sorry for not getting back sooner.

Context: I'm a WPF programmer with 2 years experience, new to ATF and WinForms.

General questions:

* How do the schema-generated objects compare to DependencyObjects?  They seem pretty similar at first glance, except that schema objects are code-genned, and DepObjs need to be handwritten.

* How do WPF commands compare to ATF's command library?  How does this affect things like ContextMenus?

* Do you have a good sample for blending WinForms and WPF?

* Is it possible to see the new WPF sample app before January?

On Monday, November 24, 2014 7:11:28 PM UTC-8, julianneh wrote:

julianneh

unread,
Dec 3, 2014, 10:00:46 PM12/3/14
to authoring-to...@googlegroups.com
Sorry Jason, I didn't forget about you. I've been out of the office and catching up.

You're right that schema generated objects and DependencyObjects have some similarities, but DependencyObjects just provide the functionality for working with WPF's dependency property system (automatically updating the view when the data changes, etc) while schema generated objects provide a ton of functionality for working with the ATF DOM. This document has some more info about creating a data model with a schema and the benefits it gives you: https://github.com/SonyWWS/ATF/wiki/Simple-DOM-Editor-Programming-Discussion#Data_Model

Upon reflection, it might be a good idea for us to add the option to autogenerate DependencyObject info along with the DOM metadata. There are certainly cases where you'd want both, and that would save a lot of typing!

WPF commands and ATF commands are also very similar, but again the ATF version adds DOM integration. I'd recommend sticking with the ATF commands, particularly if you're using DOM. More info about ATF commands here: https://github.com/SonyWWS/ATF/wiki/Using-Commands-in-ATF

And as a matter of fact, the existing WPF sample app (Samples\WinGui\WpfApp) combines WinForms and WPF. I guess it is good for something :)

- Julianne

Jason Batchkoff

unread,
Dec 4, 2014, 1:39:41 PM12/4/14
to authoring-to...@googlegroups.com
Code-genning the DepObjs: I think this is a fantastic direction.  However, I'd recommend generating an INotifyPropertyChanged based class instead of a DepObj.  The point being with DepObj's the lower-level MS code ends up owning the data, which conflicts with the DomNode owning the data.  I used a setup similar to this at a prior studio to great effect.  There were some caveats, but overall, it made writing WPF tools incredibly fast since you have a REAL CLASS to code against and all the other cruft (file management, undo redo) was done for you as well.  

I can go into some more detail on how I think it could work, if you are interested.  Are there other things that you'd have to get done before working on this?  Or can you start today?  ;)

I'll do more exploring on the links you provided.  Thanks.

I've also cobbled together a WPF & WinForms app, so that's a fun start, though I'm certain I've got some subtle bug somewhere...

julianneh

unread,
Dec 4, 2014, 2:41:56 PM12/4/14
to authoring-to...@googlegroups.com
I won't be starting on the code gen today ;) But I have added it to my task list. I like the idea of going with INotifyPropertyChanged instead of DependencyObject. I'd love to hear more about your experience with this, either now if you've got time to write it up, or I can touch base with you when I'm ready to start working on it and we can talk about it then. Thanks!

May I ask what you're doing that requires a mixed WPF-WinForms app? I had assumed most of our users would prefer to stick with one or the other as much as possible, so I'm curious about why you're starting with both.

- Julianne

Jason Batchkoff

unread,
Dec 4, 2014, 5:53:19 PM12/4/14
to authoring-to...@googlegroups.com
WinForms + WPF: 

My motivation is to transition things that were written in WinForms to WPF.  The problem is that I won't have a huge block of time to transition an entire tool to WPF.  I'd take the approach of converting a particular control (i.e., property editor) and replacing it in our set of tools, then doing some other non-tools work for a few months, then come back and replace a core control (say the circuit drawing part of the circuit editor) when we have time / priority.

Object Generation:

The main point centers around what you expose and what basic types you support.  There are three main types that I saw: Basic fields (int's, object's, etc), Lists (represented as ObservableCollection<>'s), and Dictionaries (which were...interesting).  It doesn't look like Dict's are supported in DOM? So you will likely dodge a bullet there.

The basic format was also pretty simple.  Let's say you had some type 'Foo'.  I'll talk about how our types related with 'FooNPC' being derived from INotifyPropertyChanged, and 'FooNode' being the Schema Generated one (equivalent to the DomNode).

Creation:
We allowed you to either create a new FooNPC but you had to specify a File that it was created in.  I'd see this equivalent to the DomDocument?  It'd internally create a DomNode for you and subscribe to events, then raise the events for a new Node being added to the Document.  There were some tricky bits here if you needed to create all your sub-objects, and make sure the events were raised appropriately. 

Additionally, if you somehow got a Node, we allowed you to simply wrap an existing FooNode with a FooNPC, and it just worked.

Exposure:
We defaulted to exposing all 'real' properties on the FooNode in the FooNPC, but also a quick access to the FooNode itself, if you needed to do something 'weird'.  Most of the time accessing the FooNPC was enough.

The interesting point here was 'How do we expose the attributes on the Properties?' since we often used them in our template selectors and controls.  I believe we ended up with just another Dict<string, List<FieldAttribute>> with the field name being the Key.  We also had another list of attributes exposed for the Type as well.  It's interesting to me because we effectively created another meta data system to access these things.  Perhaps we could so something better here?  

Additionally, I didn't particularly like working with the Dict.  I'd've preferred a class that was all the attributes (I mean, we are code genning, right?) as pure fields themselves (i.e., class FooFieldAttributes{ public bool IsFile; public string FileInitialDirectory; public ColorEnum ColorType; } ) This attr class would help with binding to controls that need things like InitialDirectory for a FilePicker control.

We also made the FooNPC a partial class so we could extend it in simple ways in a sister C# file.  (Providing some simple sorting functions, for example.)  The point was that the bare minimum class wasn't always sufficient to work with as pure data.

Resulting Code:

The nice thing was that a command could just do 'var obj = new FooNPC(App.CurrentDocument, "NewFooObject");' and then do 'obj.Field = 184.0f' which was very nice for random folks supporting us (Game Programmers / Tech Art).  Or just have a ListView in XAML bind directly to the object list, e.g. {Binding Path="SomeList"} then write some DataTemplate's, and implement 'add item' and 'remove item' commands and be done.

Another nice thing was: If tools code depended on a field existing, and the format was changed (field removed or something), the code would have compile errors which were obvious.

We also took advantage of having static strings for PropertyNames so we could respond to OnPropertyChanged() easily too.

Does that all make sense?

We also had to deal with a bunch of crazy other things (ownership (and correct cloning), communicating over a network connection, multiple clients) but they are all a bit beside the point.

julianneh

unread,
Dec 4, 2014, 7:20:23 PM12/4/14
to authoring-to...@googlegroups.com
Thanks for the detailed info about your object generation solution! I'll make sure to handle the use cases you described. I think ours may be simpler because we've already got all the document handling, attribute management, etc, we just need to add the support for INotifyPropertyChanged. With ATF's support for Adaptation, it's easy to use the object as whichever type you need at the moment - more info on that here: https://github.com/SonyWWS/ATF/wiki/Adaptation-in-ATF

And okay, that makes sense re. WinForms and WPF. I thought you were starting a new tool. Let me know if you have questions along the way!

Des Griffiths

unread,
Dec 5, 2014, 12:19:31 PM12/5/14
to authoring-to...@googlegroups.com
Hi Jason,

Regarding WPF support in ATF, you probably want to start by looking at ObservableDomNodeAdapter. This derives from DomNodeAdapter but supplies the INotifyPropertyChanged interface.

public abstract class NamedNode : ObservableDomNodeAdapter
{
        [ObservableDomProperty("name")]
        public string Name
        {
            get { return GetAttribute<string>(schema.namedType.nameAttribute); }
            set { DomNode.SetAttribute(schema.namedType.nameAttribute, value); }
        }
}

Note the ObservableDomProperty attribute. This allows the property changed event to be raised automatically when the underlying DomNode attribute "nameAttribute" changes. It will fire the correct "Name" property change. The attribute is optional and you can still call your own PropertyChanged handler, although beware, if you do this you will have to subscribe to the AttributeChanged event of the DomNode in order to handle things like undo/redo changes.

Also note, that when the property is a single child DomNode it is necessary to use the ObservableDomChild attribute instead.

For ObservableCollection (INotifyCollectionChanged) support there is the ObservableDomListAdapter:

public IObservableCollection<IFolder> Folders
{
     get { return GetObservableChildList<IFolder>(schema.folderType.folderItemChild);
}

To allow ATF Adaption to work in XAML, there's the DomBindingAdapterObject, add this to your DomNodeAdapter view model:

        public object As
        {
            get
            {
                return m_adapterObject ?? (m_adapterObject = new DomBindingAdapterObject(DomNode, true));
            }
        }

Then from XAML you can do something like this:

                            <Image>
                                <Image.Source>
                                    <PriorityBinding>
                                        <Binding Path="As.AssetThumbnailAdapter.Image" IsAsync="True"/>
                                        <Binding Path="As.AssetThumbnailAdapter.LoadingImage" />
                                    </PriorityBinding>
                                </Image.Source>
                            </Image>

The "As." calls into the adaption code to obtain the AssetThumbnailAdapter DomNodeAdapter if it exists, on your data.

Hope that helps,
Des.

Jason Batchkoff

unread,
Dec 10, 2014, 3:42:32 PM12/10/14
to authoring-to...@googlegroups.com
Thanks that does help.

I imagine most of this is what Julianne is going to generate automatically?

Also, just curious, why is the NamedNode class in the example abstract?

Des Griffiths

unread,
Dec 11, 2014, 4:02:23 AM12/11/14
to authoring-to...@googlegroups.com
Hi Jason,

Yep, these properties could be generated by the DomGen tool.

Re: abstract, no special reason, copy and pasted from our codebase - the schema type was set to abstract.

Regards,
Des.

Jason Batchkoff

unread,
Jan 29, 2015, 1:32:11 PM1/29/15
to authoring-to...@googlegroups.com
FWIW, I made a copy of the DomGen tool, and switched the code in SchemaGen.Generate() to create the WPF adapters instead of normal adapters. 

The '-a' parameter pretty much does everything I wanted.  But I:
1) Changed the base type to ObservableDomNodeAdapter.
2) Put the ObservableDomProperty attr on each of the properties.
3) Returned IObservableCollection's instead of IList's.

I was vaguely wondering if this might in fact be the best default, since it still provides the minimum interface for WinForms code (or other adapters), and additionally provides a usable interface for WPF .  I'll leave that decision up to you all.  ;)

julianneh

unread,
Jan 29, 2015, 10:14:48 PM1/29/15
to authoring-to...@googlegroups.com
Thanks for the info Jason, this all sounds good. I've been tied up with getting ready for today's ATF 3.9 release, but I should be able to start digging into this soon!
Reply all
Reply to author
Forward
0 new messages